美文网首页
Objective-C回调

Objective-C回调

作者: Emiya_zhang | 来源:发表于2018-04-08 19:21 被阅读0次

    1.回调机制

    所谓回调就是讲一段可执行的代码与特定的一个事件绑定起来,当事件发生时就会调用这段代码。

    Objective-C的回调有四种途径实现

    1. 目标-动作对(target-action): 事件发生时,向特定的对象发送特定的消息。接收消息的对象为目标,消息的选择器(selector)是动作。
    2. 辅助对象(helper objects):事件发生时,向遵守特定协议的辅助对象发送消息。委托对象(delegate)和数据源(data source)是常见的辅助对象。
    3. 通知(notification): 苹果公司添加了一种称之为通知中心(notification center)的对象。程序开始前,可以告知消息中心“某个对象正在等待某些特定的通知。当通知出现时,向指定的对象发送特定的消息”。即事件发生时,相关对象向通知中心发布通知,然后由通知中心将通知发生给等待通知的对象。
    4. Block对象(Blocks): Block是一段可执行代码,声明一个Block对象,在事件发生时,调用该Block对象。

    事件驱动的程序需要一个等待事件发生的负责,OS X和iOS系统用NSRunloop的类(运行循环)来等待事件的发生,示例代码如下:

    #import <Foundation/Foundation.h>
    int main(int argc, const char * argv[])
    {
        @autoreleasepool{
            [[NSRunLoop currentRunLoop] run];
        }
        return 0;
    }
    
    Runloop

    runloop是一种闲时循环,等待事件的发生,runloop会有一个autorelease pool,runloop更新时[pool drain],向池中的对象发送release消息。

    2.具体实现

    (1)目标-动作对(target-action)

    以NSTimer对象每隔2S,让一个TSLogger对象设置时间和打印时间。

    //  TSLogger.h
    #import <Foundation/Foundation.h>
    
    @interface TSLogger : NSObject
    
    @property (nonatomic) NSDate * lastTime;
    
    -(NSString *)lastTimeString;
    -(void)updateLastTime:(NSTimer *)t;
    
    @end
    
    //  TSLogger.h
    #import "TSLogger.h"
    
    @implementation TSLogger
    
    -(NSString *)lastTimeString
    {
        static NSDateFormatter *dateFormater = nil;
        if(!dateFormater)
        {
            dateFormater = [[NSDateFormatter alloc] init];
            [dateFormater setTimeStyle:NSDateFormatterMediumStyle];
            [dateFormater setDateStyle:NSDateFormatterMediumStyle];
            NSLog(@"create dateFormater");
        }
        return [dateFormater stringFromDate:self.lastTime];
    }
    
    -(void)updateLastTime:(NSTimer *)t
    {
        NSDate *now = [NSDate date];
        [self setLastTime:now];
        NSLog(@"just set time to %@", self.lastTimeString);
        
    }
    
    @end
    
    
    //  main.m
    #import <Foundation/Foundation.h>
    #import "TSLogger.h"
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool{
            TSLogger *logger = [[TSLogger alloc] init];
            __unused NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0
                                                              target:logger
                                                           selector:@selector(updateLastTime:)
                                                            userInfo:nil repeats:YES];
            [[NSRunLoop currentRunLoop] run];
        }
        return 0;
    }
    

    先看main.m中在NSTimer对象timer中设置了目标-动作对的目标为TSLogger对象logger,动作为updateLastTime:,时间是每隔2S,重复进行。而在TSLogger对象中进行了具体的动作方法的实现。

    这就是目标-动作对的大体用法,即在指定的时刻触发事件,情况比较简单,而且只做了一件事。

    (2)辅助对象(helper objects)

    辅助对象有委托对象数据源两种,我们先看委托对象

    <1>委托对象

    委托(delegate)就是将一件属于委托者做的事情交给被委托者来处理。受委托完成任务的对象称之为委托对象

    创建一个委托协议;

    对于委托者:

    1. 委托者声明要委托的属性,该属性遵守协议;
    2. 委托者在自己实现的方法通过遵守协议的属性,调用协议内的方法;
    3. 委托者设置好需要委托对象维护的属性

    对于委托对象:

    1. 委托对象实现委托协议所定义的方法。

    举例如下

    有个人想要开公交赚钱,但是只有自己一个人忙不过来,需要找个售票的帮他卖票和告知情况。这里我们假定每2S来一个乘客。

    1. 创建一个Bus协议,描述需求是需要会卖票和报告卖票信息。对应第一步
    2. 在公交车类里声明一个卖票者属性,这个属性应由外界赋值。对应A.1
    3. 公交车上路后(startRun),代码内部的sellTicket由准守该协议的onePerson执行。对应A.2
    //公交车的使用协议
    @protocol BusProtocol <NSObject>
    
    -(void)sellTicket;
    -(void)reportSituation;
    @end
    
    //公交车类的声明
    @interface Bus : NSObject
    
    @property(nonatomic,strong)id<busProtocol>onePerson;
    -(void)startRun;
    @end
    
    //公交车类的实现
    @implementation Bus
    
    -(void)startRun
    {
            if(self.onePerson)
            {
                [self.onePerson sellTicket];
                [self.onePerson reportSituation];
            }
    }
    
    @end
    

    我们需要的卖票对象如下,它遵守协议实现了卖票的方法。对应B.1

    //委托对象seller类的声明
    @interface Seller : NSObject <busProtocol>
    
    @end
    
    //委托对象seller类的实现
    @implementation Seller
    
    -(void)sellTicket
    {
            NSLog(@"开始售票!");
    }
    -(void)reportSituation
    {
            NSLog(@"完成售票!");
    }
    @end
    

    最后在main中,设置委托者里需要委托对象维护的属性,即onePerson是委托对象seller。对应A.3

    #import <Foundation/Foundation.h>
    #import "Bus.h"
    #import "Seller.h"
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool{
            Bus * busone = [[Bus alloc] init];
            Seller * sell = [[Seller alloc] init];
            busone.onePerson = (id) sell;
            __unused NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0
                                                              target:busone
                                                            selector:@selector(startRun)
                                                            userInfo:nil repeats:YES];
            [[NSRunLoop currentRunLoop] run];
            
        }
        return 0;
    }
    

    结果每来一个客人(每2S),Bus都会委托Seller对象进行售票和汇报。

    2018-04-08 16:51:40.768918+0800 test[1612:289822] 开始售票!
    2018-04-08 16:51:40.768946+0800 test[1612:289822] 完成售票!
    2018-04-08 16:51:42.769788+0800 test[1612:289822] 开始售票!
    2018-04-08 16:51:42.769820+0800 test[1612:289822] 完成售票!
    

    委托可以向一个对象发送多个回调。

    (3)通知(notification)

    一个对象发生变化时,多个对象想要获得这个变化的通知,比如我们修改了系统的时区,很多对象会想要知晓这一变化。系统的时区发生变化时,会向通知中心发送NSSystemTimeZoneDidChangeNotification通知,然后通知中心会将该通知转发给相应的观察者们。

    实例代码如下,将airlineHostess(空姐)和airlineBoy作为观察者,修改时区后,airlineHostess和airlineBoy广播换时区了,一个中文,一个英文。

    //  airlineHostess.h
    #import <Foundation/Foundation.h>
    
    @interface airlineHostess : NSObject
    -(void) report;
    @end
    
    //  airlineHostess.m
    #import "airlineHostess.h"
    
    @implementation airlineHostess
    -(void) report
    {
        NSLog(@"亲爱的乘客们,我们换时区啦!");
    }
    @end
    
    

    main.m中注册观察者

    #import <Foundation/Foundation.h>
    #import "airlineHostess.h"
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool{
            airlineHostess * beauty = [[airlineHostess alloc] init];
            [[NSNotificationCenter defaultCenter]
                                    addObserver:beauty
                                    selector:@selector(report)
                                    name:NSSystemTimeZoneDidChangeNotification
                                    object:nil];
            airlineBoy * handsome = [[airlineBoy alloc] init];
            [[NSNotificationCenter defaultCenter]
                                    addObserver:handsome
                                    selector:@selector(reportEnglish)
                                    name:NSSystemTimeZoneDidChangeNotification
                                    object:nil];
            [[NSRunLoop currentRunLoop] run];
        }
        
        return 0;
    }
    
    

    运行后,打开系统的时间与偏好设置修改时区,结果如下。

    2018-04-08 19:18:29.488975+0800 test[1786:359257] 亲爱的乘客们,我们换时区啦!
    2018-04-08 19:18:29.516014+0800 test[1786:359257] Dear passengers, we are in a new time zone!
    

    (4)Block对象(Blocks)

    Block知识点较多,将放入下一篇文章讲解

    block对象

    相关文章

      网友评论

          本文标题:Objective-C回调

          本文链接:https://www.haomeiwen.com/subject/ccmmhftx.html