UI基礎(五)之代理、通知的小結

林堯彬發表於2020-04-04

代理:

這裡只強調一些注意點:

注意點(一):代理為什麼要用weak修飾?

答:為了防止記憶體洩漏

程式碼如下:

HSDog.h類
@protocol HSDogDelegate <NSObject>
@end

@interface HSDog : NSObject

@property (nonatomic, weak) id<HSDogDelegate>delegate;

@end


HSDog.m
#import "HSDog.h"

@implementation HSDog

- (void)dealloc
{
    NSLog(@"HSDog----銷燬");
}

@end

HSPerson.h
@interface HSPerson : NSObject

@end

HSPerson.m
#import "HSPerson.h"
#import "HSDog.h"

@interface HSPerson()<HSDogDelegate>
/** 強引用dog*/
@property (nonatomic, strong) HSDog *dog;
@end

@implementation HSPerson

- (instancetype)init
{
    self = [super init];
    if (self) {
        // 例項化dog
        self.dog = [[HSDog alloc] init];
        self.dog.delegate = self;

    }
    return self;
}

- (void)dealloc
{
    NSLog(@"HSPerson----銷燬");
}

@end

ViewController.m
#import "ViewController.h"
#import "HSPerson.h"

@interface ViewController ()
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    HSPerson *person = [[HSPerson alloc] init];

}
@end

程式碼其實可以不用看,只需要知道幾點:

(1)Person *p = [Person alloc]init];在ARC中預設是強指標指向,但p指標存放在棧區,出了其所在的括號就會被回收掉

(2)self.dog = [[Dog alloc]init];注意的是:self.dog呼叫set方法,方法內部其實是:__strong Dog* _dog; 因為有: 

/** 強引用dog*/
@property (nonatomic, strong) HSDog *dog;

所以知道_dog是strong修飾的.

(3)而dog是依附於person物件的,也就是說self.dog指標的存亡取決於person物件是否消失,如果person物件沒有消失,那麼self.dog就一直存在著。

同理self.dog.delegate= self也是如此

綜上所述:代理需要用weak修飾,至於用strong會不會產生記憶體洩漏也要根據具體程式碼和指標指向來判斷。

 







 

 

 

 

1.需要掌握:

•通知的釋出
 
•通知的監聽
 
•通知的移除
通知中心(NSNotificationCenter)

 

小結:其實很簡單:通知流程就是:一個釋出通知的物件把通知釋出給通知中心,通知中心負責把通知傳遞給通知的接收者.
 
 

 

插曲:一直以來都是建立UI專案,但不能忘記OC 專案是怎麼建立的,看下圖:

 第一個最簡單的通知的使用:過程分析:

注意點:新增監聽者必須寫在傳送通知之前

1.通知中心傳送通知,(前提是必須有一個通知,可以直接在傳送通知中寫出來,不用提前建立通知物件).

2.通知中心傳送了通知之後,會找前面是否有監聽者監聽我的這個通知,如果有,就會找到這個監聽者物件.

3.找到監聽者物件後會呼叫監聽者物件的方法,完成實現通知的方法.

4.注意:不能忘記通知的使用完畢後,要移除監聽者.

 

5.注意:有沒有想過:為什麼一般我寫監聽者物件實現的方法中帶的引數是通知型別的?可以帶別的型別的引數麼?

答:是不能帶別的型別的引數的,該方法存在的意義在於:我傳給監聽者一個通知,並要你實現一個方法,目的是為了讓你看到

我通知的具體內容,因為我傳遞的就是通知,該方法也稱之為通知方法,用於傳遞通知的具體資訊,怎麼看呢,只需要帶上通知型別的引數列印出來就可以了.

News.h
#import <Foundation/Foundation.h>

@interface News : NSObject

@property (nonatomic,copy) NSString *newsName;



@end

News.m

#import "News.h"

@implementation News

@end

Person.h

#import <Foundation/Foundation.h>

@interface Person : NSObject


@property (nonatomic,copy) NSString *name;


- (void)show:(NSNotification *)notification;

@end

Person.m

#import "Person.h"

@implementation Person

- (void)show:(NSNotification *)notification{
    
    
    NSDictionary *dict = notification.userInfo;


    NSLog(@"%@",dict[@"吳亦凡"]);
    NSLog(@"監聽到通知了  監聽人 %@--- %@",self.name,notification);
    
}




- (void)dealloc{

#pragma mark -- 移除監聽者
    
//    在MRC中,非ARC 中,需要呼叫下面的方法
//    [super dealloc];
    
//    NSLog(@"移除監聽者");
    [[NSNotificationCenter defaultCenter]removeObserver:self];
    
    

}
@end

main.m

//
//  main.m
//  03-通知的使用
//
//  Created by apple on 16/7/15.
//  Copyright © 2016年 itcast. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "News.h"
#import "Person.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        
        News *sinaNew = [[News alloc]init];
        
        sinaNew.newsName = @"sina";
        
        News *wangNew = [[News alloc]init];
        
        wangNew.newsName = @"wangyi";
        
        Person *p1 = [[Person alloc]init];
        
        p1.name = @"zhangsan";
        
        
        Person *p2 = [[Person alloc]init];
        p2.name = @"lisi";
        
     
#pragma mark -- 通知
        
        // 1. 引數1: name =>通知的名字
        // 2. 引數2: object =>釋出通知的物件
        // 3. 引數3: userInfo=>額外資訊
        NSNotification *notification = [NSNotification notificationWithName:@"yule" object:sinaNew userInfo:@{@"趙薇事件":@"黑社會"}];
        
        NSNotification *notification2 = [NSNotification notificationWithName:@"yule" object:wangNew userInfo:@{@"吳亦凡":@"做壞事"}];
        
        
        NSNotification *notification3 = [NSNotification notificationWithName:@"junshi" object:sinaNew userInfo:@{@"南海":@"仲裁不通過"}];
        
#pragma  mark -- 釋出通知
        
        //1. 現有通知中心
        // 通知中心 是單例設定模式, 它有一個預設的方法,可以得到這個物件[NSNotificationCenter defaultCenter]
        NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
        
        
        //2. 釋出通知
        // 將建立的通知釋出出去
//        [notificationCenter postNotification:notification];
        
#pragma mark -- 監聽通知
        
        //新增監聽者
        //<#(nonnull id)#> 代表監聽者物件
        //@selector   代表監聽到訊息後,所呼叫的方法
        // name 釋出的通知名字  傳入nil代表無論是什麼通知,都接受
        //object 釋出通知的物件  傳入nil代表無論哪個通知物件釋出的資訊都接受
        [notificationCenter addObserver:p1 selector:@selector(show:) name:nil object:nil];
        
        [notificationCenter addObserver:p2 selector:@selector(show:) name:@"yule" object:nil];
        
        
        
        [notificationCenter postNotification:notification];
        [notificationCenter postNotification:notification2];
        [notificationCenter postNotification:notification3];
        
        
        NSLog(@"程式碼執行結束");
        
        
        
    }
    return 0;
}

代理事例二:

main.m

//
//  main.m
//  01-通知的使用
//
//  Created by apple on 16/7/17.
//  Copyright © 2016年 itcast. All rights reserved.
//

#import <Foundation/Foundation.h>

#import "Baby.h"
#import "Father.h"
#import "Mother.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        Father *father = [[ Father alloc]init];
        
        Mother *mother = [[Mother alloc]init];
        
        
      
        Baby *baby = [[Baby alloc]init];
        
// 通知的使用: 新增監聽者
        // 第一個引數 id--> 監聽者物件
        // 第二個引數 selector--> 監聽到後呼叫的方法
        // 第三個引數 name --> 釋出通知的名字
        // 第四個引數 object -> 釋出通知的物件
        [[NSNotificationCenter defaultCenter]addObserver:father selector:@selector(notification:) name:nil object:baby];

        
        
        [[NSNotificationCenter defaultCenter]addObserver:mother selector:@selector(notification:) name:nil object:baby];
        
        
        [baby babyKu];
        
        [baby babyNiao];
        
        
    }
    return 0;
}

Baby.h

//
//  Baby.h
//  01-通知的使用
//
//  Created by apple on 16/7/17.
//  Copyright © 2016年 itcast. All rights reserved.
//

#import <Foundation/Foundation.h>
@class Baby;


@interface Baby : NSObject





-(void)babyKu;

- (void)babyNiao;

@end

Baby.m

//
//  Baby.m
//  01-通知的使用
//
//  Created by apple on 16/7/17.
//  Copyright © 2016年 itcast. All rights reserved.
//

#import "Baby.h"

@implementation Baby


-(void)babyKu{

    NSLog(@"寶寶在哭");
    

    //1. 通知的使用
//    NSNotification
    
    //1.1 釋出通知
    
    // name---> 通知的名字
    // object -->釋出通知的物件
    // userInfo-->額外資訊
    [[NSNotificationCenter defaultCenter]postNotificationName:@"ku" object:self userInfo:nil];
    
   

}

- (void)babyNiao{


    NSLog(@"寶寶尿床了");
    
    
    [[NSNotificationCenter defaultCenter]postNotificationName:@"niao" object:self userInfo:nil];
    
    
   
    
    
    
    
}

@end

Father.h

//
//  Father.h
//  01-通知的使用
//
//  Created by apple on 16/7/17.
//  Copyright © 2016年 itcast. All rights reserved.
//

#import <Foundation/Foundation.h>


@interface Father : NSObject 

@end

Father.m

//
//  Father.m
//  01-通知的使用
//
//  Created by apple on 16/7/17.
//  Copyright © 2016年 itcast. All rights reserved.
//

#import "Father.h"

@interface Father ()

@end

@implementation Father


- (void)notification:(NSNotification *)notification{

    NSLog(@"%@",notification);
    
    NSString *name = notification.name;
    
    
    if ([@"ku" isEqualToString:name]) {
        [self lookBabyKu];
    }else{
    
        [self lookBabyNiao];
    }

}


- (void)dealloc{

    //銷燬監聽者
    [[NSNotificationCenter defaultCenter]removeObserver:self];

}


- (void)lookBabyKu{

    NSLog(@"爸爸 照顧嬰兒哭");
}


- (void)lookBabyNiao{

    NSLog(@"爸爸 照顧嬰兒尿");

}


@end

 

 小結:
通知:很簡單,就四步:
第一步:我需要傳遞資料的時候(一般多控制器就是逆傳),釋出通知:
//傳送通知
        [[NSNotificationCenter defaultCenter] postNotificationName:@"TZ" object:self userInfo:nil];

第二步:哪個控制器需要監聽我這個通知,我就在那個控制器裡面(具體位置是可以獲取到目標控制器的方法中),新增監聽者物件

//用通知來傳遞資料
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cancelLoginMessage) name:nil object:listController];

第三步:實現第二步裡面的方法

 
#pragma mark -- 實現通知方法
- (void)cancelLoginMessage{
    //使用者名稱和密碼清空
            _nameField.text = @"";
            _passwordField.text = @"";
            //關閉自動登入和記住密碼switch
            _recordSwitch.on = NO;
            _autoSwitch.on = NO;
            //登入按鈕
            _loginBtn.enabled = NO;
    
            //儲存在使用者偏好設定的資料也要恢復預設值
            [[NSUserDefaults standardUserDefaults] setBool:NO forKey:KRecordSwitch];
            [[NSUserDefaults standardUserDefaults] setBool:NO forKey:KAutoSwitch];
            [[NSUserDefaults standardUserDefaults] setObject:@"" forKey:KUserName];
            [[NSUserDefaults standardUserDefaults] setObject:@"" forKey:KPassWord];
}

第四步:很關鍵,別忘了在這個下面移除監聽者

#pragma mark -- 銷燬監聽者
- (void)dealloc{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

 

 
 
 
 代理和通知區別:
代理只能有一個代理物件,通知可以有多個監聽者,也就是所謂的一對一和一對多的區別:
因為代理:
baby.delegate= father;
baby.delegate = mather;
當我這樣設定的時候,其實很明顯知道,baby的代理物件是下面的mather ,這是根據賦值運算的基本原理得出的,所以代理只能有一個代理物件.
而通知,誰成為我通知的監聽者,誰就能做通知物件.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

轉載於:https://www.cnblogs.com/yiyuanchenfeng/p/6034647.html

相關文章