前提
- 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 に対応させる
書き替え前のソースコード
Hoge.h
@interface Hoge : NSObject<NSCoding>
@property (nonatomic, assign) int32_t value;
@property (nonatomic, strong) Fuga* fuga;
@property (nonatomic, strong) NSArray<Fuga>* fugas;
@end
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
Fuga.h
@interface Fuga : NSObject<NSCoding>
@property (nonatomic, assign) int32_t value;
@end
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
変更点
Hoge.h
- @interface Hoge : NSObject<NSCoding>
+ @interface Hoge : NSObject<NSSecureCoding>
Hoge.m
+ +(BOOL)supportsSecureCoding { return true;}
Fuga.h
- @interface Fuga : NSObject<NSCoding>
+ @interface Fuga : NSObject<NSSecureCoding>
Fuga.m
+ +(BOOL)supportsSecureCoding { return true;}
Step 2 archivedDataWithRootObject:
unarchiveObjectWithDataunarchiveObjectWithData:
を書き換える
書き替え前のソースコード
SomeModel.h
@interface SomeModel
@property(nonatomic, strong) Hoge* hoge;
-(void)saveData;
-(void)loadData;
@end
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
変更点
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;
+ }
}