1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

NSNotificationを使って設定パネルを実装する

Last updated at Posted at 2019-11-18

概要

-w821

NotificationCenterはブロードキャスト、Delegateは指定されたクラスへ通知。

  • そういうときに便利なのがNSNotificationです。
  • 通知名をキーとして、通知を監視するクラスと通知を送信するクラス間で情報をやり取りします。
  • (欠点としては飛び道具なので、適当に使うと構造が不透明になったり、クラスが密結合になってしまいかねない所でしょうか。)

GitHub

参考

  • ヒレガス本

コード全体

メイン画面(通知を受け取る側)

AppDelegate.m
# import "AppDelegate.h"
# import "PreferencesController.h"
@interface AppDelegate ()
@property (weak) IBOutlet NSWindow *window;
@property PreferencesController *preferencesController;
// 本来はAppDelegateに書かず、MainMenuウィンドウのためのWindowControllerを建てる
@property (weak) IBOutlet NSTextField *needsSendingMailLabel;
@property (weak) IBOutlet NSTextField *mailAddressLabel;
@end

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    // Insert code here to initialize your application
    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
    [notificationCenter addObserver:self
                           selector:@selector(handleSendingMailChange:)
                               name:IKESendingMailChangedNotification
                             object:nil];
    
    [notificationCenter addObserver:self
                           selector:@selector(handleMailAddressChange:)
                               name:IKEMailAddressChangedNotification
                             object:nil];
    
    PreferencesController *preferencesController = [PreferencesController new];
    [preferencesController showWindow:self];
    _preferencesController = preferencesController;
}

- (void)applicationWillTerminate:(NSNotification *)aNotification {
    // Insert code here to tear down your application
}


// Notification Receive Methods
- (void)handleSendingMailChange:(NSNotification *)notification {
    NSLog(@"(RECEIVE)メール送信有無の変更通知");
    BOOL needsSendingMail = [notification.userInfo[IKENeedsSendingMailKey] boolValue];
    if (needsSendingMail) {
        [_needsSendingMailLabel setStringValue:@"必要"];
    } else {
        [_needsSendingMailLabel setStringValue:@"不要"];
    }
}

- (void)handleMailAddressChange:(NSNotification *)notification {
    NSLog(@"(RECEIVE)メールアドレスの変更通知");
    [_mailAddressLabel setStringValue:notification.userInfo[IKEMailAddressKey]];
}

@end

設定画面(通知を送る側)

PreferencesController.h
# import <Cocoa/Cocoa.h>

NS_ASSUME_NONNULL_BEGIN

// 通知名には衝突を避けるためにPrefixをつけると良い。
extern NSString *const IKESendingMailChangedNotification;
extern NSString *const IKEMailAddressChangedNotification;

// userinfo用のキー
extern NSString *const IKENeedsSendingMailKey;  // メール有無
extern NSString *const IKEMailAddressKey;       // メールアドレス

@interface PreferencesController : NSWindowController
@end

NS_ASSUME_NONNULL_END
PreferencesController.m
# import "PreferencesController.h"

NSString *const IKESendingMailChangedNotification = @"IKESendingMailChanged";
NSString *const IKEMailAddressChangedNotification = @"IKEMailAddressChanged";
NSString *const IKENeedsSendingMailKey            = @"needsSending";
NSString *const IKEMailAddressKey                 = @"mailAddress";

@interface PreferencesController () <NSTextFieldDelegate>
@property (weak) IBOutlet NSTextField *mailAddressTF;

@end

@implementation PreferencesController

- (id)init {
    if (self = [super initWithWindowNibName:[self className] owner:self]) {
    }
    
    return self;
}

- (void)windowDidLoad {
    [super windowDidLoad];
    
    // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
    
}

- (IBAction)sendingMailCheckBoxClicked:(NSButton *)sender {
    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
    NSLog(@"(POST)メール有無の変更通知");
    NSNumber     *needsSendingMail = [NSNumber numberWithBool: sender.state];
    NSDictionary *userinfoDic      = @{IKENeedsSendingMailKey : needsSendingMail};
    [notificationCenter postNotificationName:IKESendingMailChangedNotification
                                      object:self
                                    userInfo:userinfoDic];
}

// MARK:- NSTextField Notification Methods
- (void)controlTextDidChange:(NSNotification *)aNotification {
    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
    NSLog(@"(POST)メールアドレスの変更通知");
    NSDictionary *userinfoDic = @{IKEMailAddressKey : _mailAddressTF.stringValue};
    [notificationCenter postNotificationName:IKEMailAddressChangedNotification
                                      object:self
                                    userInfo:userinfoDic];
}
@end

コード詳細

設定画面(通知を送る側)

PreferencesController.h

// 通知名には衝突を避けるためにPrefixをつけると良い。
extern NSString *const IKESendingMailChangedNotification;
extern NSString *const IKEMailAddressChangedNotification;

// userinfo用のキー
extern NSString *const IKENeedsSendingMailKey;  // メール有無
extern NSString *const IKEMailAddressKey;       // メールアドレス
  • 通知名のグローバル定数を作成する
  • 同様に通知内容の(NSDictionary *)userinfoを受け取るときのために、キーのグローバル定数を作成する

PreferencesController.m

NSString *const IKESendingMailChangedNotification = @"IKESendingMailChanged";
NSString *const IKEMailAddressChangedNotification = @"IKEMailAddressChanged";
NSString *const IKENeedsSendingMailKey            = @"needsSending";
NSString *const IKEMailAddressKey                 = @"mailAddress";
  • PreferencesController.hで宣言した定数に具体的な値をつける
    • 通知名には衝突を避けるためにPrefixをつけると良い。
@interface PreferencesController () <NSTextFieldDelegate>
  • NSTextFieldの値変更を監視するためNSTextFieldDelegateを採用する
- (IBAction)sendingMailCheckBoxClicked:(NSButton *)sender {
    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
    NSLog(@"(POST)メール有無の変更通知");
    NSNumber     *needsSendingMail = [NSNumber numberWithBool: sender.state];
    NSDictionary *userinfoDic      = @{IKENeedsSendingMailKey : needsSendingMail};
    [notificationCenter postNotificationName:IKESendingMailChangedNotification
                                      object:self
                                    userInfo:userinfoDic];
}
  • 通知を送るときの手順は以下の通り。
  • NSNotificationCenterオブジェクトを作成する
  • 通知する際に送りたい情報を(NSDictionary *)userinfoDicに登録する
  • NSNotificationCenterオブジェクトのメソッドpostNotificationNameで通知を送信する
    • objectに文字列を指定しているコードを見たことがあるが、別にuserinfoがあるので、ここにはselfを指定するのが筋だと思う。
    • objectは例えば、通知先でselfが何か、つまり通知元がどこかを判別するのに使ったりするのではないかと思う。
- (void)controlTextDidChange:(NSNotification *)aNotification {
  • やっていることは同じなので割愛

メイン画面(通知を受け取る側)

AppDelegate.m

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    // Insert code here to initialize your application
    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
    [notificationCenter addObserver:self
                           selector:@selector(handleSendingMailChange:)
                               name:IKESendingMailChangedNotification
                             object:nil];
  • 通知を受け取る設定の手順は以下の通り。
  • NSNotificationCenterオブジェクトを作成
  • addObserver...で登録
    • addObserver:監視する主体
    • selector:通知があった際に実行する関数
    • name:通知名
    • object:通知送信元の指定
  • 詳細:addObserver:selector:name:object:
// Notification Receive Methods
- (void)handleSendingMailChange:(NSNotification *)notification {
    NSLog(@"(RECEIVE)メール送信有無の変更通知");
    BOOL needsSendingMail = [notification.userInfo[IKENeedsSendingMailKey] boolValue];
    if (needsSendingMail) {
        [_needsSendingMailLabel setStringValue:@"必要"];
    } else {
        [_needsSendingMailLabel setStringValue:@"不要"];
    }
}
  • 上記のselectorで指定した関数が、通知を受け取った際に呼ばれる
  • 通知の際に送った(NSDictionary *)userinfo notification.userInfo[IKENeedsSendingMailKey]のように受け取ることができる。
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?