zoukankan      html  css  js  c++  java
  • [objective-c] 04

     

    本章主要讲解回调的概述以及具有目标-动作回调接口的组件如何使用。

    1.回调

    回调,也叫事件触发,在底层开发中也就是服务或中断服务。其产生过程较为复杂,所以我们在此不会展开讲解。只是单纯讲解如何配置回调。

    在使用一些较为复杂,或者和用户有交互类型的组件时。我们通常需要根据组件触发的事件来做出相应的响应。

    比如我们使用一个开关控制一个灯。我们在编写代码的时候并不能准确的知道开关的状态,也就无法确定灯的状态。所以我们只能在开关状态发生改变的时候,获取开关的状态且根据开关的状态对灯的状态进行改变。

    这时候就需要开关有一个能反馈自身状态的机制。这种机制便成为回调机制。

    我们在编程中可以通过回调机制让代码在运行的过程中捕获开关状态的改变点,从而实现对灯的控制。

    回调机制具体有三种表现形式:

    1. 目标-动作回调
    2. 委托模式回调
    3. 代码块回调

    下面我们展开讲解目标-动作回调。

    2.目标-动作回调

    目标:接收事件反馈的对象。比如开关要反馈自身状态,此时接收反馈信息的对象便成为目标。目标对象为id类型,因为在设计开关时,并不知道开关的使用者是什么类型的对象。在代码中通常用target来表示目标对象。

    动作:事件反馈所要触发的方法。比如开关要反馈给我状态改变的信息,在代码中的具体表现形式为,通过调用我的某个方法来进行告知。动作对象为SEL类型。

    SEL类型是OC语言为存储方法名创造的变量类型。同时还创造了一个运算符,用于把一个方法名转换成一个SEL值。

    SEL test = @selector(方法名);
    

    在编程中,如果我们想使用开关,并且要根据开关状态的反馈做出不同的处理,那么我们就需要设置开关的反馈目标和反馈动作。

    能够设置反馈目标和反馈动作的组件我们称为具有目标动作回调接口的组件。

    3.使用具有目标动作回调接口的组件

    在真实情况下,具有目标动作接口的组件都是复杂类组件。所以在本章讲解中,使用虚拟的组件来进行OC语法上的学习。

    首先我们来了解两个虚拟的组件,开关和灯

    灯的声明文件

    @interface Light : NSObject
    
    -(void)turnOff; // 开灯
    -(void)turnOn; // 关灯
    
    @end
    

    可见灯的操作很简单,只有开灯和关灯两个方法。

    开关的声明文件

    typedef enum : NSUInteger {
        SwitchStateOff, // default
        SwitchStateOn,
    } SwitchState;
    
    @interface Switch : NSObject
    
    @property(nonatomic,assign,readonly)SwitchState currentState;
    
    -(void)addChangeStateTarget:(id)target Action:(SEL)action;
    
    @end
    

    开关有一个只读属性,为当前开关的状态,其状态变量为枚举类型

    • SwitchStateOff 表示关闭状态
    • SwitchStateOn 表示开启状态

    开关还有一个addChangeStateTarget方法,通过该方法为这个开关设置反馈对象和反馈动作,以实现让反馈对象收到开关状态的改变信息。

    下面我们假设有一个房间,房间中有一个开关和一个灯。代码实现如下:

    @interface Room : NSObject
    
    @end
    
    
    @interface Room ()
    
    @property(nonatomic,strong) Light * aLight;
    @property(nonatomic,strong) Switch * aSwitch;
    
    -(void)changeState:(Switch *)s;
    
    
    @end
    
    @implementation Room
    
    - (instancetype)init
    {
        self = [super init];
        if (self) 
        {
            self.aLight = [[Light alloc] init];
            self.aSwitch = [[Switch alloc] init];
            //设置反馈对象和反馈方法
            [self.aSwitch addChangeStateTarget:self Action:@selector(changeState:)];
        }
        return self;
    }
    
    -(void)changeState:(Switch *)s
    {
        if (self.aSwitch.currentState == SwitchStateOff)
        {
            [self.light turnOn];
        }
        else
        {
            [self.light turnOff];
        }
    }
    
    
    @end
    

    上段代码中我们依次做了如下事情

    • 创建了一个Room类的延展
    • 在延展中声明了灯和开关的属性
    • 在初始化方法中为组件分配内存
    • 在初始化方法中设置组件反馈的目标和反馈动作
    • 实现反馈方法中的具体处理逻辑

    这样当代码开始运行,开关状态被用户改变之后,灯的状态也会随之改变。当然,这段代码是虚拟的。在之后章节中我们会接触到可以真正运行的代码。还需要同学们努力学习。

  • 相关阅读:
    [bbk4999] 第100集 第12章 数据移植 06
    [bbk4992] 第98集 第12章 数据移植 04
    [bbk0000] 第101集 第12章 数据移植 08 本章案例 > 使用ORACLE_DATAPUMP擎创建外部表
    PL/SQL
    [zz]Python:time.clock() vs. time.time()
    MVC简介
    ajax_get/post_两级联动
    Ajax
    JAVAUML
    类与接口的区别
  • 原文地址:https://www.cnblogs.com/lqios/p/4272019.html
Copyright © 2011-2022 走看看