[精通Objective-C]对象和消息传递

[精通Objective-C]对象和消息传递

参考书籍:《精通Objective-C》【美】 Keith Lee

目录

  • 精通Objective-C对象和消息传递

    • 目录
    • 对象
      • 创建对象
      • 初始化对象
      • 重构Atom类并创建子类
      • 工厂方法
    • 消息传递
      • 发送消息
      • 消息转发
    • 附录前一章节创建的Atom类

对象

创建对象

NSObject类中用于创建类实例(即对象)的方法

+(id) alloc

通过alloc方法,可以创建对象,下面以创建一个Atom对象为例

//创建一个属于Atom类的对象,并为它分配一个数据类型为id的变量
id atom = [Atom alloc];
//与上面语句等价,显示定义变量的类型,失去灵活性,但可以获得静态类型检查
Atom *atom = [Atom alloc];

初始化对象

alloc方法为对象分配了内存,并将它的实例变量设置为0,但是alloc方法既没有将该对象的实例变量初始化为适当的值,也没有为这个对象准备其他必须的对象和资源。因此自定义的类还应该实现完成初始化的过程的方法。

NSObject类中用于初始化对象的方法:

-(id) init

下面以Atom类的init方法为例:

-(id) init{
    //调用父类的init方法,结果赋给调用对象
    if ((self = [super init])) {
        //初始化
        _chemicalElement = @"None";
    }
    return self;
}

重构Atom类并创建子类

编译器自动补全属性时,创建的是一个作用范围为@private的支持实例变量,无法被该类的子类访问。可以重构该类,将这个变量的作用范围设置为@protected。

@interface Atom : NSObject
//重构Atom类,声明作用范围为@protected的支持实例变量
{
    @protected NSUInteger _protons;
    @protected NSUInteger _neutrons;
    @protected NSUInteger _electrons;
    @protected NSString *_chemicalElement;
    @protected NSString *_atomicSymbol;
}
//之前声明的属性和方法
@property(readonly) NSUInteger protons;
@property(readonly) NSUInteger neutrons;
@property(readonly) NSUInteger electrons;
@property(readonly) NSString *chemicalElement;
@property(readonly) NSString *atomicSymbol;

-(NSUInteger) massNumber;
@end

创建一个Atom类的子类Hydrogen,并使用新的可以接受参数的初始化方法。

Hydrogen.h

#import "Atom.h"

@interface Hydrogen : Atom

//声明初始化方法
-(id) initWithNeutrons:(NSUInteger)neutrons;
@end

Hydrogen.m

#import "Hydrogen.h"

@implementation Hydrogen
{
    @private HydrogenHelper *helper;
}

//实现初始化方法
-(id) initWithNeutrons:(NSUInteger)neutrons{
    if ((self = [super init])) {
        _chemicalElement = @"Hydrogen";
        _atomicSymbol = @"H";
        _protons = 1;
        //使用传入参数为实例变量赋值
        _neutrons = neutrons;
    }
    return self;
}
@end

工厂方法

工厂方法是指用于创建和初始化类的便捷方法

在Hydrogen.h中声明

+(id) hydrogenWithNeutrons:(NSUInteger)neutrons;

在Hydrogen.m实现

+(id) hydrogenWithNeutrons:(NSUInteger)neutrons{
    //创建一个Hydrogen对象并初始化,然后返回这个对象
    return [[self alloc] initWithNeutrons:neutrons];
}

之后我们就可以用两种不同的方法来完成对象的初始化了

        //普通方法
        Hydrogen *atom1 = [[Hydrogen alloc] initWithNeutrons:1];
        //工厂方法
        Hydrogen *atom2 = [Hydrogen hydrogenWithNeutrons:2];

消息传递

消息传递是OOP中的用于调用对象中方法的机制。接收消息的对象(接收器)会在运行时决定调用其实例的哪个方法。实例方法可以访问对象的实例变量和实例方法。

发送消息

向对象发送消息的格式:

[接收器 消息名称1:参数1 消息名称2:参数2 ...]

同时Objective-C还为类方法提供了语言级的支持:

[类名 消息名称1:参数1 消息名称2:参数2 ...]

之前的[Hydrogen hydrogenWithNeutrons:2]就是向Hydrogen类发送消息。

消息转发

在运行时,接收器都会通过解释消息,确定需要调用哪个方法。Objective-C提供了消息转发机制,当对象收到与其方法集不匹配的消息时,通过消息转发机制可以使对象能够在收到无法识别的信息时执行各种逻辑,如将消息发送给能够作出回应的其他接收器或是既不处理也不使程序抛出运行时错误,默默吞下消息。

Objective-C为NSObject类的子类提供了两类消息转发选项。

快速转发:

//重写NSObject类的该方法,将该方法转发给其他对象,就像是将对象的实现代码与转发对象合并到了一起,类似于类实现的多重继承行为
-(id) forwardingTargetForSelector:(SEL)aSelector

标准(完整)转发:

//重写NSObject类的该方法,可以让对象使用消息中的全部内容(目标,方法名和参数)
-(void) forwardInvocation:(NSInvocation *)anInvocation

下面来为Hydrogen类添加快速转发机制。

首先需要创建一个辅助类HydrogenHelper,该类负责处理一个名为factoid的Hydrogen类无法处理的方法。

HydrogenHelper.h

#import <Foundation/Foundation.h>

@interface HydrogenHelper : NSObject

-(NSString *) factoid;

@end

HydrogenHelper.m

#import "HydrogenHelper.h"

@implementation HydrogenHelper

-(NSString *) factoid{
    return @"The lightest element and most abundant chemical substance.";
}

@end

再更新Hydrogen类的代码


@implementation Hydrogen
//添加实例变量HydrogenHelper
{
    @private HydrogenHelper *helper;
}

-(id) initWithNeutrons:(NSUInteger)neutrons{
    if ((self = [super init])) {
        _chemicalElement = @"Hydrogen";
        _atomicSymbol = @"H";
        _protons = 1;
        _neutrons = neutrons;

        //创建并初始化HydrogenHelper对象
        helper = [[HydrogenHelper alloc] init];
    }
    return self;
}

+(id) hydrogenWithNeutrons:(NSUInteger)neutrons{
    return [[self alloc] initWithNeutrons:neutrons];
}

//重写NSObject类的forwardingTargetForSelector:(SEL)aSelector方法
-(id) forwardingTargetForSelector:(SEL)aSelector{
    //如果HydrogenHelper对象能够处理该消息,则将消息转发给HydrogenHelper对象
    if ([helper respondsToSelector:aSelector]) {
        return helper;
    }
    return nil;
}

@end

为了使Hydrogen类能够接收factoid方法,还需再添加一个分类,在其中声明factoid方法(不需要实现)

Atom+Helper.h(由于不需要实现方法可以把自动创建出来的Atom+Helper.m删掉)

#import "Atom.h"

//也可以将Atom改为Hydrogen
@interface Atom (Helper)

//声明factoid方法
-(NSString *) factoid;

@end

最后就可以通过消息转发功能,向Hydrogen对象发送factoid方法了

Hydrogen *atom = [Hydrogen hydrogenWithNeutrons:2];
[atom factoid];

附录:前一章节创建的Atom类

Atom.h

#import <Foundation/Foundation.h>

@interface Atom : NSObject

@property(readonly) NSUInteger protons;
@property(readonly) NSUInteger neutrons;
@property(readonly) NSUInteger electrons;
@property(readonly) NSString *chemicalElement;

-(NSUInteger) massNumber;
@end

Atom.m

#import "Atom.h"

@implementation Atom

-(id) init{
    if ((self = [super init])) {
        _chemicalElement = @"None";
    }
    return self;
}

-(NSUInteger) massNumber{
    return self.protons + self.neutrons;
}

@end
时间: 2024-10-09 17:02:39

[精通Objective-C]对象和消息传递的相关文章

objc_msgSend消息传递学习笔记 – 对象方法消息传递流程

在Effective Objective-C 2.0 – 52 Specific Ways to Improve Your iOS and OS X Programs一书中,tip 11主要讲述了Objective-C中的消息传递机制.这也是Objective-C在C的基础上,做的最基础也是最重要的封装. Static Binding And Dynamic Binding C中的函数调用方式,是使用的静态绑定(static binding),即在编译期就能决定运行时所应调用的函数.而在Obje

Java从入门到精通04-类、对象

Java语言是面向对象的,计算机语言的发展向接近人的思维方式演变: 类和对口箱的区别和联系1.类是抽象的,概念的,代表一类事物,比如人类.猫类...2.对象是具体的,实际的,代表一个事物,比如张三.李四...3.类是对象的模板,对象是类的一个个体.实例: 一个全面类的定义模板: package 包名; class 类名 extends 父类 implements 接口名{ 成员变量; 构造方法; 成员方法; } 类的成员方法的参数可以是多个,方法可以没有返回值: 构造方法是类的一种特殊方法,它的

精通Hibernate——Java对象在JVM中的生命周期

当应用程序通过new语句创建一个对象时,JVM会为这个对象分配一块内存空间,只要这个对象被引用变量引用,他就一直存在在内存当中.当这个对象不被任何对象引用的时候,他的生命周期就意味着结束,JVM会在适当的时候回收这个对象.下面通过代码来演示下生命周期: Customer c = new Customer("Tom",new HashSet()); Order o1 = new Order("Tom_order001",null); Order o2 = new Or

精通Hibernate——域对象之间的关系

在域模型中.类之间存在四种关系 1.关联(Association) 类之间的引用关系,能够有一对一.一对多和多对多,比如customer与order之间就是一对多 public class Order{ // 与order对象关联的Customer对象 private Customer customer; } 以上代码建立了从Order类到Customer类的关联,相同也能够建立从Customer类对Order类的关联,因为一个Customer对象会相应多个Order对象,因此,应该在Custo

[精通Objective-C]进阶技巧:使用运行时系统API

[精通Objective-C]进阶技巧:使用运行时系统API 参考书籍:<精通Objective-C>[美] Keith Lee 什么是运行时系统? 目录 精通Objective-C进阶技巧使用运行时系统API 目录 动态加载可选包 创建命令行程序 创建可选包 传入包路径 使用可选包 运行时系统API 动态代理 创建实现横切功能的协议和类 编写代理类 添加代理的目标类 测试动态代理程序 动态加载可选包 下面是使用NSbundle API动态加载自己编写的框架包的示例,共需要创建两个工程,一个命

Objective-C的对象模型和runtime机制

内容列表 对象模型(结构定义,类对象.元类和实例对象的关系) 消息传递和转发机制 runtime系统功能理解 对象模型 结构定义 对象(Object): OC中基本构造单元 (building block),用于存储和传递数据. 可以在objc.h的文件中查找到对象结构的定义,如下所示即对象结构为Class类型的isa,而Class是 objc_class结构类型指针.objc_class即我们理解的类对象结构,其也包含一个isa类对象结构指针. 类和对象的最终实现都是一种数据结构,(subcl

objc_msgSend消息传递学习笔记 – 消息转发

该文是 objc_msgSend消息传递学习笔记 – 对象方法消息传递流程 的基础上继续探究源码,请先阅读上文. 消息转发机制(message forwarding) Objective-C 在调用对象方法的时候,是通过消息传递机制来查询且执行方法.如果想令该类能够理解并执行方法,必须以程序代码实现出对应方法.但是,在编译期间向类发送了无法解读的消息并不会报错,因为在 runtime 时期可以继续向类添加方法,所以编译器在编译时还无法确认类中是否已经实现了消息方法. 当对象接受到无法解读的消息后

[精通Objective-C]运行时系统

[精通Objective-C]运行时系统 参考书籍:<精通Objective-C>[美] Keith Lee 目录 精通Objective-C运行时系统 目录 运行时系统概述 对象消息 选择器 方法签名 使用对象消息 动态类型 动态绑定 动态方法决议 动态加载 内省 运行时系统的组成部分 编译器 运行时系统库 元类 与运行时系统交互 运行时系统概述 Objective-C拥有相当多的动态特性,这些特性在运行程序时发挥作用,而不是在编译或链接代码时发挥作用.Objective-C运行时系统实现了

[精通Objective-C]预处理器

[精通Objective-C]预处理器 参考书籍:<精通Objective-C>[美] Keith Lee 目录 精通Objective-C预处理器 目录 预处理器概述 预处理器语言 预处理器指令 宏 预处理器概述 预处理根据一系列预定义规则,使用一些字符序列替换输入的字符序列.这些操作主要分为以下三步: Created with Rapha?l 2.1.0输入源文件执行文本翻译将输入的源文件拆分成多个记号将输入代码转换为预处理器语言 1.文本翻译:预处理会将输入的源文件拆分成代码行.使用单个