Edited at

SwiftのOptional型を練習する

More than 3 years have passed since last update.

Swiftで「ええやん!」と興奮しつつも「なんでエラーなん?」と頭を悩まされ続けているOptional型。

この場合はOptinal型でこう省略して書けるよ!的な記事を見ては忘れてと繰り返しているので一気に理解を深めておきたいと思っています。


型宣言とアンラップ

Optional型の書き方として「!」と「?」が頻出します

宣言時の「!?」とアンラップ時の「!?」は意味合いが違います

ここが混乱のポイントだと思います


型宣言における「!」と「?」

Optional型宣言の省略系となる

// 以下は同義

var str :String? = "string"
var str :Optional<String> = "string"

// 以下は同義

var str :String! = "string"
var str :ImplicitlyUnwrappedOptional<String> = "string"

if ([self.delegate responsToSelector:@selector(aaa)]) {
[self.delegate aaa]
}

self.delegate?.aaa?()

Optional<型>ImplicitlyUnwrappedOptional<型>はnilを代入することができる型です。(非Optional型ではエラー)

これらは元の型とは異なります。なので元の型の持っているfuncなどにアクセスすることはできません。

アクセスと同様にも元の型への代入もできません。型エラーです。

そのため、元の方にアンラップすることでfuncなどへのアクセスします。


Optional<型>ImplicitlyUnwrappedOptional<型>の違い

Optional<型>は「nilが代入できる型」

ImplicitlyUnwrappedOptional<型>は加えて「使用時にForced Unwrappingされる型」


アンラップにおける「!」と「?」

変数をアンラップする方法として4つある。

「!」はForced Unwrappingする。

「?」はOptional Chainingする。


  • Forced Unwrapping

  • Optional Chaining

  • Optional Binding

  • ImplicitlyUnwrappedOptionalで宣言する


Forced Unwrapping

var str :String? = "string"

var unwrapped :String = str!

「!」を使う

Optional型を元の方に戻す

Optional型にnilが入っているとエラー

nilだとエラー


Optional Chaining

var str :String? = nil

str?.lowercaseString

「?」を使う、少し癖が有る

Optional型を返しそれをchainしていく、nilの場合はnilを返す

アンラップといえどOptional型を返すとはどういうことかというと

// arr自体もOptional型で値もOptional型

var arr :Array<String?>? = [nil, "two"]
// arrを「?」でOptional型をアンラップして、Forced Unrappingで元の値へ変換する
arr?[1]!.daikobay // -> が結果はOptional型となる

2行目のアンラップ処理を詳しく言うと

* Optionalを「?」でアンラップ、nilでないので元の型のArrayとして扱う

* Arrayとして扱うので変数へアクセスできるが、次の値がnilの可能性もあるのでOptional型としてChainingしていく

* 中のStringはOptionalなので「!」でForced Unwrappingし元の型へ変換

* しかし、arrを「?」しOptional Chainingしているので元の型からOptional型へ変換される

とこんな感じでOptional Chainingはnilでもエラーとしないので元の型へ変換してアクセス可能にした後、Optional型へ戻す

nilを許容する


Optional Binding

var str :String? = "string"

if var s :String = str {
println(s)
}

とnilでなくアンラップ可能ならif内部へ進む

nilでなければ処理する


問題集

ということで問題集でも用意します。


aa

aa



notice.swift

playgroundは優しいので即座にエラーメッセージを出してくれます

問題集を使う場合はplaygroundを使わないことをお勧めします


question-1


question-1

// 以下を正しいコードに直そう

func getAny () -> AnyObject {
var any :NSString? = "NSString"
return any
}



answer-1



// 返り値はOptional型じゃないので

func getAny () -> AnyObject {

var any :NSString? = "NSString"

return any!

}

// もしくは

func getAny () -> AnyObject? {

var any :NSString? = "NSString"

return any

}


question-2


question-2

// 2行目はOptional型?非Optional型?

var arr :Array<String?>? = ["one", "two"]
arr?[0]!



answer-2



Optional型

「!」がついているが、先に「?」でOptional Chainingとなっているので「!」がついていてもOptional型に変換される

例えば

(arr?[0])!

としていれば最後に「!」で元の型に戻るので非Optional型になる


question-3


question-3

// varやfuncの宣言はいじらず"I'm bob"と出力されるように修正しよう

// このままでは'Optional("I\'m Optional(\"bob\")")'と出力される

class Person
{
var name :String?

init (name: String)
{
self.name = name
}

func say () -> String? {

return "I'm \(self.name)"
}
}

var bob :Person? = Person(name: "bob")

println(bob?.say()!)



answer-3



sayを以下のように実装

if var greet :String = self.name {

return "I'm (greet)"

}

return nil

sayの呼び出し方を以下のように変更

println((bob?.say())!)


以上