ページ

2014年12月20日土曜日

[Obj-C, Swift] 設定部分の実装などを想定した NSUserDefaults を用いた値保持の基礎(前半)

【Obj-C, Swift】設定部分の実装などを想定した NSUserDefaults を用いた値保持の基礎(前半)

はじめに

前回は Modal Segue の基本的実装を Objective-C と Swift で行いました。

【Obj-C, Swift】 Modal Segue 基本(前半)
 http://milanista224.blogspot.com/2014/12/oc-swift-modal-segue-1.html

【Obj-C, Swift】 Modal Segue 基本(後半)
 http://milanista224.blogspot.com/2014/12/oc-swift-modal-segue-2.html

設定画面に遷移し設定いじって元の画面に戻って適用。などの実装はわりとあるのかなと思います。
今回は UserDefault を用いて値を保持し,その値を別の ViewController で用いる実装を行います。
目指す動作像は次項を参照してください。
Objective-C と Swift で行い,どんな違いがあるのかを見ていきます。
前半は,Objective-C での実装です。やり方は何通りかあると思います。
例によって,
初級の方の役に立てばいいんですけど,個人的な趣味,備忘録なので気にしません!

目指す動作

主に設定の場面での実装を考慮している。

起動したら文字列と BOOL に関するラベルが 2 つ。初期値はそれぞれ"NO DATA"。
下部には Settings ボタンがあり,設定画面に遷移する。
設定画面ではテキストフィールドと UISwitch があり,
テキストフィールドに文字列を入力し,UISwitch もいじる。
Back ボタンを押し,遷移元の画面に戻ると設定画面で設定した文字列,BOOL 値に更新される。
これらの値は次回起動以降もリセットされることなくそのままであり続ける。

1 回作ってしまえば使いまわせるのでいいですね。(そんなたいそうなものではありませんが。)
Delegate を用いた値渡し(画面遷移)も近日やりたいですね。

ユーザデフォルトとは

データの保持をしたいときに使う。例えばアプリの設定など。
アプリを終了しても次回起動時に設定が保持されている必要があるときですね。
流れは下記の通りです。
  1. UserDefault 宣言
  2. キー値をそれぞれの形式で保存
  3. 値をすぐに反映させる(必要な場合は)
  4. 必要なところで必要なときにキーから値を抽出
値の保存,抽出形式は int 型,文字列型,NSArray 型などいろいろあります。
詳細は下記 URL などを参照してください。
http://iphone-tora.sakura.ne.jp/nsuserdefaults.html

実装

画像はクリックで RAW 画像見れます。見難いところあればお使いください。
まずは,Objective-C から。
Single View Application → プロジェクト名適当 → Objective-C
新しく ViewController を用意して下記画像のように部品をそれぞれ配置し,
Storyboard Segue Identifier 名(任意)をつける。(present modality)


次に File -> New -> File... -> Cocoa Touch Class で,
新たに SettingsViewController を SubClass:UIViewController で作成。
2 つ目の ViewCotroller のクラスにする。


ViewController.h と SettingsViewController.h は下記画像の感じで。
それぞれ Storyboard と紐付けします。

ViewController.h


SettingsViewController.h


次にメソッドファイルです。
ViewController.m にはユーザデフォルトの値の更新と設定画面遷移のコードを書きます。
初回起動時にはデータはないのであるときとの条件分岐を書きます。
下記は一部。全体のコードは今回のコードの項をごらんください。

-(void)load {

    // UserDefault 宣言
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    
    // すでに設定でテキストフィールドに入力されている場合
    if ([[NSUserDefaults standardUserDefaults] objectForKey:@"TextField_Status"] != nil) {
        
        // キーに登録されている文字列を抽出,表示
        // 保存は SettingsViewController.m の仕事
        NSString* value_string = [defaults stringForKey:@"TextField_Status"];
        _stringLabel.text = value_string;
    } else {
        _stringLabel.text = @"NO DATA"; // 初回起動 or 未設定
    }
    
    // UISwitch の値(初回起動など区別)
    // 初回起動
    if ([[NSUserDefaults standardUserDefaults] objectForKey:@"Switch_Status"] == nil) {
        _boolLabel.text = @"NO DATA";  // 初回起動 or 未設定
    } else {
        
        // キーに登録されているBOOL値を抽出,反映
        BOOL value_switch = [defaults boolForKey:@"Switch_Status"];
        if (value_switch == 1) {
            _boolLabel.text = @"YES";
        } else {
            _boolLabel.text = @"NO";
        }
    }
}

また,遷移先から戻ってきたときに値を更新するために,viewWillAppear に再度呼ぶように書いておく。

// 設定画面から戻ってきたときに load 関数呼び出し
- (void) viewWillAppear:(BOOL)animated {
    
    [self load];
}

あとは,SettingsViewCotroller へ遷移するコードを書けばいいです。(前回のを参照)


続いて,SettingsViewController.m のコードですが,
同じく初回起動時にはデータはないのであるときとの条件分岐を書きます。
テキストフィールド,UISwitch の値が変化したときの処理(下記参照)の中に

【iOS】UISwitch の値取得や値変更での処理(基礎)
 http://milanista224.blogspot.com/2014/09/uiswitch-basic1.html


  
    // 値が変化(ユーザが変更)したら呼ばれる
    // TextFiled ver
    [_textField addTarget:self action:@selector(textFieldAction:) forControlEvents:UIControlEventEditingDidEndOnExit];
    [self.view addSubview:_textField];
    
    // Switch ver
    [_switchBtn addTarget:self action:@selector(switchAction:)
         forControlEvents:UIControlEventValueChanged];
    [self.view addSubview:_switchBtn];

それぞれの値をキーに保存する処理を書きます。

// テキストフィールドに入力(変化)された場合に呼ばれる // 入力値をキーに保存 - (IBAction)textFieldAction:(id)sender { // UserDefault 宣言 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; // TextField_Status というキーに入力された文字列を保存 [defaults setObject:_textField.text forKey:@"TextField_Status"]; // 値をすぐに反映させる [defaults synchronize]; } // スイッチの値が変化したら呼ばれる // 入力値をキーに保存 - (IBAction)switchAction:(id)sender { // UserDefault 宣言 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; // スイッチがオンかオフか if(_switchBtn.on == YES) { // Switch_Status というキーにスイッチの状態を保存 [defaults setBool:YES forKey:@"Switch_Status"]; } else { // Switch_Status というキーにスイッチの状態を保存 [defaults setBool:NO forKey:@"Switch_Status"]; } // 値をすぐに反映させる [defaults synchronize]; }

あとは元の画面に戻る処理などを書いて終わりです。
動作させてみると下記のようになります。
http://youtu.be/E1mTpu5BhDs


今回のコード

今回のサンプルコード:https://github.com/MilanistaDev/OCModalNSUserDefaultsTest

ViewController.h
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@property (weak, nonatomic) IBOutlet UILabel *stringLabel;
@property (weak, nonatomic) IBOutlet UILabel *boolLabel;

@property (weak, nonatomic) IBOutlet UIButton *settingsBtn;
- (IBAction)settingsAction:(id)sender;

@end

ViewController.m
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 表示関係は全部 load 関数に任せる(自作関数)
    [self load];
}

// 設定画面から戻ってきたときに load 関数呼び出し
- (void) viewWillAppear:(BOOL)animated {
    
    [self load];
}

-(void)load {
    
    // UserDefault 宣言
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    
    // すでに設定でテキストフィールドに入力されている場合
    if ([[NSUserDefaults standardUserDefaults] objectForKey:@"TextField_Status"] != nil) {
        
        // キーに登録されている文字列を抽出,表示
        NSString* value_string = [defaults stringForKey:@"TextField_Status"];
        _stringLabel.text = value_string;
    } else {
        _stringLabel.text = @"NO DATA"; // 初回起動 or 未設定
    }
    
    // UISwitch の値(初回起動など区別)
    // 初回起動
    if ([[NSUserDefaults standardUserDefaults] objectForKey:@"Switch_Status"] == nil) {
        _boolLabel.text = @"NO DATA";  // 初回起動 or 未設定
    } else {
        
        // キーに登録されているBOOL値を抽出,反映
        BOOL value_switch = [defaults boolForKey:@"Switch_Status"];
        if (value_switch == 1) {
            _boolLabel.text = @"YES";
        } else {
            _boolLabel.text = @"NO";
        }
    }
}

// Settings ボタンが押されたとき modal_segue1 の遷移
- (IBAction)settingsAction:(id)sender {
    
    [self performSegueWithIdentifier:@"modal_segue1" sender:self];
    
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

SettingsViewController.h
#import <UIKit/UIKit.h>

@interface SettingsViewController : UIViewController

@property (weak, nonatomic) IBOutlet UITextField *textField;
- (IBAction)textFieldAction:(id)sender;

@property (weak, nonatomic) IBOutlet UISwitch *switchBtn;
- (IBAction)switchAction:(id)sender;

- (IBAction)backAction:(id)sender;

@end

SettingsViewController.m
#import "SettingsViewController.h"

@interface SettingsViewController ()

@end

@implementation SettingsViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self main_method];
}

-(void)main_method {
    
    // UserDefault 宣言
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    
    // すでにテキストフィールドに入力されている場合
    if ([[NSUserDefaults standardUserDefaults] objectForKey:@"TextField_Status"] != nil) {
        
        // キーに登録されている文字列を抽出,表示
        NSString* value_string = [defaults stringForKey:@"TextField_Status"];
        _textField.text = value_string;
    }
    
    // UISwitch の値(初回起動など区別)
    // 初回起動
    if ([[NSUserDefaults standardUserDefaults] objectForKey:@"Switch_Status"] == nil) {
        _switchBtn.on = NO;
    } else {
        
        // キーに登録されているBOOL値を抽出,反映
        BOOL value_switch = [defaults boolForKey:@"Switch_Status"];
        if (value_switch == 1) {
            _switchBtn.on = YES;
        } else {
            _switchBtn.on = NO;
        }
    }
    
    // 値が変化(ユーザが変更)したら呼ばれる
    // TextFiled ver
    [_textField addTarget:self action:@selector(textFieldAction:) forControlEvents:UIControlEventEditingDidEndOnExit];
    [self.view addSubview:_textField];
    
    // Switch ver
    [_switchBtn addTarget:self action:@selector(switchAction:)
         forControlEvents:UIControlEventValueChanged];
    [self.view addSubview:_switchBtn];
    
}

// テキストフィールドに入力(変化)された場合に呼ばれる
// 入力値をキーに保存
- (IBAction)textFieldAction:(id)sender {
    
    // UserDefault 宣言
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    
    // TextField_Status というキーに入力された文字列を保存
    [defaults setObject:_textField.text forKey:@"TextField_Status"];
    
    // 値をすぐに反映させる
    [defaults synchronize];
}


// スイッチの値が変化したら呼ばれる
// 入力値をキーに保存
- (IBAction)switchAction:(id)sender {
    
    // UserDefault 宣言
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    
    // スイッチがオンかオフか
    if(_switchBtn.on == YES) {
        // Switch_Status というキーにスイッチの状態を保存
        [defaults setBool:YES forKey:@"Switch_Status"];
    } else {
        // Switch_Status というキーにスイッチの状態を保存
        [defaults setBool:NO forKey:@"Switch_Status"];
    }
    // 値をすぐに反映させる
    [defaults synchronize];
}

// メイン画面に戻る
- (IBAction)backAction:(id)sender {
    
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    
    // キーボードを閉じる。
    [_textField resignFirstResponder];
    
    return YES;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

おわりに

主に設定部分の実装などを想定した NSUserDefaults を用いた値保持の
基礎的なサンプルアプリを Objective-C で実装しました。
これ以上長くなりそうなら Github だけでもいい気がしますね^^:
ここだけの話,このサンプル作っているときにとんでもないミスに気がついてしまいました。
終わり次第,FLAT Weather Clock の Bug-fix に取り組もうと思います。
Swift 版(後半)は出来次第書きます。
ご覧いただきありがとうございました。ここはこうしたほうがいいなどの
ご意見もいただけると勉強になります。おねがいします。

Twitterボタン
Twitter:@milanista_2nd
Apple 関係のこと,ガジェット系,ブログ更新などいろいろつぶやいています。
よろしければフォローお願いします!

初めてのアプリ作りました。無料なのでよろしければ是非。
 
FLAT Weather Clock

カテゴリ: ユーティリティ, 天気
価格:無料

Category: Utilities, Weather
Price: Free



 サポートページ日本語版:リンク
 Support Website(English):LINK

2014.12.20 Milanista



TAG index

0 件のコメント:

コメントを投稿