5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

struct と class で異なる Failable Initializers

Last updated at Posted at 2016-01-13

EDIT: Swift 2.2 ではこの問題は解決していますので、記事を参考にする際はご留意ください。2016.5

Failable Initializers

Swift の Failable Initializers について調べていたら、 以下のような記述が出ていた。

struct Animal {
    let species: String
    init?(species: String) {
        if species.isEmpty { return nil }
        self.species = species
    }
}

Playground で試してみる確かにエラーにならない。しかし、struct を class に変えると…

class Animal {
    let species: String
    init?(species: String) {
        if species.isEmpty { return nil } // error
        self.species = species
    }
}

なんと「全てを初期化しないと nil を返して戻れないよ」と言われてしまった。

All stored properties of a class must be initialized before returning nil from an initializer.

ドキュメントもう少し下にスクロールすると、あった! class の場合の記述。

Failable Initializers for Classes

A failable initializer for a value type (that is, a structure or enumeration) can trigger an initialization failure at any point within its initializer implementation. In the Animal structure example above, the initializer triggers an initialization failure at the very start of its implementation, before the species property has been set.

For classes, however, a failable initializer can trigger an initialization failure only after all stored properties introduced by that class have been set to an initial value and any initializer delegation has taken place.

The example below shows how you can use an implicitly unwrapped optional property to satisfy this requirement within a failable class initializer:

class Product {
let name: String!
init?(name: String) {
self.name = name
if name.isEmpty { return nil }
}
}


やっぱり、class の場合は、全てを初期化してからでないとダメだってさ。チェックする項目が多くて、if 文がいくらか必要な場合はそれ毎に、無意味な値に初期値を入れて、nil を返す必要があります。

例えば、PDFを扱うクラスを例に挙げると、PDFファイルのパスを与えると、最低限そのファイルがPDFとして開ける事ができるかどうかのチェックを行うと、チェックの都度 else で値を初期化して nil を返す必要があります。

```swift
class PDFContents {
	let filePath: String
	let numberOfPages: Int
	init?(filePath: String) {
		if NSFileManager.defaultManager().fileExistsAtPath(filePath) {
			if let document = CGPDFDocumentCreateWithURL(NSURL.fileURLWithPath(filePath)) {
				self.filePath = filePath
				self.numberOfPages = CGPDFDocumentGetNumberOfPages(document)
			}
			else {
				self.filePath = filePath
				self.numberOfPages = 0
				return nil
			}
		}
		else {
			self.filePath = filePath;
			self.numberOfPages = 0;
			return nil
		}
	}
}

まぁ、この場合はファイルの有無を確認を省いて、PDFを開いてみれば if 文を減らせるかもしれませんが、チェックが多い場合には不便です。何か良い記法がないものでしょうかねぇ?そして、将来のSwiftのバージョンのどこかでは、nil を返すときは初期化していない変数があっても見逃してくれるように期待したいものです。

【環境】
Xcode7.2
Swift 2

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?