NSUserDefaultsのwrapperを書くのが面倒になったとき

  • 62
    Like
  • 1
    Comment
More than 1 year has passed since last update.

背景

NSUserDefaultsを直接使用するとkeyがわからなくなったり、typoでバグったりといろいろ大変です。そのためgetter/setterのmethodを定義することで補完を効かせたりdefaultの値を設定できるようにすることがあるかと思います。

iOS - NSUserDefaultsを使うときはWrapして使うと便利 - Qiita

しかし、毎回以下の様な感じで値ごとにgetter/setterを記述するのは大変です。

+ (NSString *)hoge {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults registerDefaults:@{@"hoge" : @"default"}];
    return [userDefaults stringForKey:@"hoge"];
}

+ (void)setHoge:(NSString *)string {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setObject:string forKey:@"hoge"];
}

そこで今回はGVUserDefaultsを使用して退屈なコードとはオサラバします。

使い方

まずはpodをinstallします。

Podfile
  pod "GVUserDefaults"

次にGVUserDefaultsのカテゴリーを定義し、その中に使いたい値をpropertyとして記述します。

GVUserDefaults+Properties.h
#import "GVUserDefaults.h"

@interface GVUserDefaults (Properties)
@property (nonatomic, weak) NSString *name;
@property (nonatomic) NSInteger age;
@end
GVUserDefaults+Properties.m
@implementation GVUserDefaults (Properties)
@dynamic name;
@dynamic age;
@end

上記の定義だけで、property経由で値をget/setすることができるようになります。

//getter
NSString *string = [GVUserDefaults standardUserDefaults].name;
//setter
[GVUserDefaults standardUserDefaults].name = @"myname";

初期値を設定したい場合はsetupDefaultsを定義します。

- (NSDictionary *)setupDefaults {
    return @{
        @"name": @"anonymous",
        @"age": @20
    };
}

このままだとUserDefaultsに登録されるkeyの名前はpropertyのと同じになってしまい、もし他にもNSUserDefaultsを使用していると衝突する恐れがあります。transformKeyを定義することで、keyにprefixをつけましょう。
なお、ここでprefixを付けても、前述のsetupDefaultsにprefixをつけるなどの変更は必要ありません。GVUserDefaultsが良きに計らってくれます。

- (NSString *)transformKey:(NSString *)key {
    // 先頭を大文字に
    key = [key stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[key substringToIndex:1] uppercaseString]];
    return [NSString stringWithFormat:@"NSUserDefault%@", key];
}

さいごに

冗長なコードをGVUserDefaultsに任せることで肝心のlogicに集中することができます。また、今回定義したgetter/setterに加え、それらを使う高次のmethodを定義すれば、userDefaultsを使用する側としてもわかりやすいインタフェースを用意できるかと思います。

GVUserDefaultsはobjc/runtime.hを使用しており黒魔術感は有りますが、もし不安に思うならGVUserDefaults.mを見てみると良いでしょう。コードは250行程度で、とてもわかり易いものとなっていますので、理解はさほど難しく無いと思います。

参考