iOSでのNullabilityの歴史（社内勉強会用）

# 目次

- Objective-C での null の扱い
- Objective-C の nullable, nonnull
- Swift の Optional
- Swift3 での仕様変更

---
# Objective-C

```objc
id nullObject = nil;
NSString *nullString = nullObject;
NSInteger length = nullString.length; // 0
NSString *uppercase = [nullString uppercaseString]; // null
```

- オブジェクトはid型
- `Type *` と宣言
- （ダウンキャストしても警告でない）
- nullオブジェクトはなにもせずnullを返す

---

# Objective-C の nullable, nonnull

```objc:ObjC.h
@interface ObjC : NSObject

@property NSString *string; // Warning: Pointer is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)
@property (nullable) NSString *nullableString;
@property (nonnull) NSString *nonnullString;

@end
```

```objc:ObjC.m
@implementation ObjC

- (instancetype)init
{
    if (self = [super init]) {
        self.string = nil;
        self.nullableString = nil;
        self.nonnullString = nil; // Warning: Null passed to a callee that requires a non-null argument
    }
    return self;
}

@end
```

- warning

---
# Swift の Optional

```swift
var string: String = "abc"
var optionalString: String? = string
var implicitlyUnwrappedOptionalString: String! = optionalString

optionalString?.uppercaseString  // Optional("ABC")
optionalString!.uppercaseString  // "ABC"
implicitlyUnwrappedOptionalString?.uppercaseString // Optional("ABC")
implicitlyUnwrappedOptionalString!.uppercaseString // "ABC"
implicitlyUnwrappedOptionalString.uppercaseString // "ABC"
```

- obj?.member で Optional Chaining
- obj! で Forced Unwrapping
- Implicitly Unwrapped Optional

```swift
var string: String = nil // Compile error: Nil cannot initialize specified type 'String'
var optionalString: String? = nil
var implicitlyUnwrappedOptionalString: String! = nil

optionalString?.uppercaseString  // nil
optionalString!.uppercaseString  // Runtime error
implicitlyUnwrappedOptionalString?.uppercaseString // nil
implicitlyUnwrappedOptionalString.uppercaseString // Runtime error
```

---
# Objective-C -> Swift

```objc:Objective-C
@interface ObjC : NSObject

@property NSString *string;
@property (nullable) NSString *nullableString;
@property (nonnull) NSString *nonnullString;

@end
```

```swift:Swift
var objc = ObjC()
objc.string.uppercaseString // Implicitly Unwrapped Optional
objc.nullableString?.uppercaseString
objc.nonnullString.uppercaseString
```

---
# Implicitly Unwrapped Optional (IUO)

```swift
class MyObject {
    var string: String
    
    init() {
        // Compile error: Return from initializer without initializing all stored properties
    }
}
```
- プロパティは、宣言時かInitializerで初期化しなければらならない
- Optional型だけは、自動的にnilで初期化される

ので、

- 例えば、システム側にインスタンス化された直後に必ず設定するプロパティは、Optional型にせざるを得ない
- という時に、String! と宣言しておけば、参照時の Unwrap が不要となる

```swift
class MyObject {
    var optionalString: String?
    var string: String!
    
    func test() {
        self.optionalString!.uppercaseString
        self.string.uppercaseString
    }
}
````

---
# IUO, Swift3で仕様変更

```swift:swift2
var notFoundImage: UIImage? = UIImage(named: "notFound.png")
var notFoundSize: CGSize? = notFoundImage?.size // nil

var beFoundImage: UIImage! = UIImage(named: "beFound.png")
var beFoundSize: CGSize = beFoundImage.size // (544.0, 184.0)

var beFoundImage2 = beFoundImage // UIImage! 型
var beFoundSize2 = beFoundImage2.size // (544.0, 184.0)
```

Swift2ではIUOは型なので、型推論も問題なしだったが、
Swift3で [「宣言時の属性」に変更された](https://github.com/apple/swift-evolution/blob/master/proposals/0054-abolish-iuo.md)

```swift:Swift3
var beFoundImage2 = beFoundImage // UIImage?型
var beFoundSize2 = beFoundImage2.size // Compile error: Value of optional type 'UIImage?' not unwrapped; did you mean to use '!' or '?'?
```

---
# （参考） Kotlin

lateinit

```kotlin
class MyObject{
    private var string: String // Compile error: Property must be initialized or be abstract
    private lateinit var lateinitString: String // OK
}
```

---
thanks