iOS12.0 でdeprecatedになってしまった unarchiveObjectWithData: と archivedDataWithRootObject: の対応方法


# 前提
* XCode で 下記2点の warning がでて対処方法がわからない人向けの記事です

```
unarchiveObjectWithData:' is deprecated: first deprecated in iOS 12.0 - Use +unarchivedObjectOfClass:fromData:error: instead
```

```
archivedDataWithRootObject:' is deprecated: first deprecated in iOS 12.0 - Use +archivedDataWithRootObject:requiringSecureCoding:error: instead
```
 
* 保存対象のクラスは、 NSCoding に対応しているものとします
* サンプルは、保存対処のクラスがさらに NSCoding に対応しているクラスを含んでいる場合にも言及しています

# 方法
## ステップ① 対象のクラスを NSSecureCoding に対応させる

### 書き替え前のソースコード

```objc:Hoge.h
@interface Hoge : NSObject<NSCoding>
@property (nonatomic, assign) int32_t value;
@property (nonatomic, strong) Fuga* fuga;
@property (nonatomic, strong) NSArray<Fuga>* fugas;
@end
```

```objc:Hoge.m
@implementation Hoge
-(id)initWithCoder:(NSCoder*)decoder {
    self = [super init];
    if( self) {
      self.value = [decorder decodeInt32ForKey::@"value"];
      self.fuga = [decorder decodeObjectForKey:@"fuga"];  
      self.fugas = [decoder decodeObjectForKey:@"fugas"];
         
    }
    return self;
}
-(void)encodeWithCoder:(NSCoder*)coder {
    [coder encodeInt32:self.maruCount forKey:@"value"];
    [coder encodeObject:self.fuga forKey:@"fuga"]; 
    [coder encodeObject:self.fugas forKey:@"fugas"];
}
@end
```

```objc:Fuga.h
@interface Fuga : NSObject<NSCoding>
@property (nonatomic, assign) int32_t value;
@end
```

```objc:Fuga.m
@implementation Fuga
-(id)initWithCoder:(NSCoder*)decoder {
    self = [super init];
    if( self) {
      self.value = [decorder decodeInt32ForKey::@"value"];         
    }
    return self;
}
-(void)encodeWithCoder:(NSCoder*)coder {
    [coder encodeInt32:self.maruCount forKey:@"value"];
}
@end
```

### 変更点

```diff_objective_c:Hoge.h
- @interface Hoge : NSObject<NSCoding>
+ @interface Hoge : NSObject<NSSecureCoding>
```

```diff_objective_c:Hoge.m
+ +(BOOL)supportsSecureCoding { return true;}
```

```diff_objective_c:Fuga.h
- @interface Fuga : NSObject<NSCoding>
+ @interface Fuga : NSObject<NSSecureCoding>
```

```diff_objective_c:Fuga.m
+ +(BOOL)supportsSecureCoding { return true;}
```

## Step 2  `archivedDataWithRootObject:`　`unarchiveObjectWithDataunarchiveObjectWithData:`を書き換える

### 書き替え前のソースコード

```objc:SomeModel.h
@interface SomeModel
@property(nonatomic, strong) Hoge* hoge;
-(void)saveData;
-(void)loadData;
@end
```

```objc:SomeModel.m
@implementation SomeModel
-(void)saveData {
   NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
   NSData* data = [NSKeyedArchiver archivedDataWithRootObject:self.hoge];
  [defaults setObject:data forKey:@"hoge"];
}
-(void)loadData {
   self.hoge = [NSKeyedUnarchiver unarchiveObjectWithData:[defaults objectForKey:@"hoge"]];
}
@end
```

### 変更点

```diff_objective_c:SomeModel.m
 -(void)saveData {
-  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
-   NSData* data = [NSKeyedArchiver archivedDataWithRootObject:self.hoge];
-  [defaults setObject:data forKey:@"hoge"];
+    NSError* error;
+    NSData* data = [NSKeyedArchiver archivedDataWithRootObject:self.hoge requiringSecureCoding:true error:&error];
+    if(error == nil) {
+         [defaults setObject:data forKey:@"hoge"];
+    }
}

 -(void)loadData {
- self.hoge = [NSKeyedUnarchiver unarchiveObjectWithData:[defaults objectForKey:@"hoge"]];
+   NSError* error;
+   // INFO:Classes に、Archive に使用している class すべてを列挙する必要がある
+   // INFO:unarchiveTopLevelObjectWithData: という class を列挙しなくてもよい便利なメソッドもあったが、こちらはiOS 14.6　で deprecatedされてしまった
+   Hoge* hoge = [NSKeyedUnarchiver unarchivedObjectOfClasses:@[[Hoge class],[Fuga class],[NSArray class]] fromData:[defaults objectForKey:@"hoge"] error:&error];
+   if(error == nil) {
+     self.hoge = hoge;
+   }
}
```