zoukankan      html  css  js  c++  java
  • Objective-C中的self与LLVM Clang新引入的instancetype

    我们知道,大部分面向对象语言对于一个类的成员方法都有一个隐含的参数。在C++、Java、C#和JavaScript中是this,而在Objective-C中则是self。当然,由于Objective-C++要完全兼容标准C++,因此关键字不能与C++有所冲突,所以用了self。


    但是,Objective-C中的self与C++、Java等编程语言中的还有一点不同——Objective-C中的self可以用于类方法,而不仅仅是成员方法,这点C++、Java等都无法做到。比如:

    @interface MyClass : NSObject
    
    + (id)createMyObject;
    
    @end
    
    @implementation MyClass
    
    - (id)init
    {
        self = [super init];
        
        NSLog(@"Hello, world");
        
        return self;
    }
    
    + (id)createMyObject
    {
        MyClass *mc = [[self alloc] init];
        
        return [mc autorelease];
    }
    
    @end

    我们看到,上述代码片段中MyClass类的createMyObject类方法中通过self来调用NSObject的类方法alloc。这里,self指向了createMyObject这个消息所发送给的类。当我们用[MyClass createMyObject]这句语句时,createMyObject中的self其实就指示了MyClass类本身。因此,可以直接用self来调用类方法alloc。


    然后利用这个特性,我们结合LLVM Clang新引入的instancetype可以编写出兼容性更强,更灵活方便的工厂方法。下面先介绍一下instancetype


    instancetype其实跟id差不多,但是它跟id不同的是,它表示一个与当前类相兼容的类型,而id则是一个通用的Objective-C对象类型引用类型。因此,如果我们要在一个类方法中返回类型为自身类型的对象,那么返回类型可以写instancetype。而上述代码片段完全符合这个要求,因此我们可以做如下改写:

    @interface MyClass : NSObject
    
    + (instancetype)createMyObject;
    - (void)dummyMethod;
    
    @end
    
    @implementation MyClass
    
    - (id)init
    {
        self = [super init];
        
        NSLog(@"Hello, world");
        
        return self;
    }
    
    + (instancetype)createMyObject
    {
        MyClass *mc = [[self alloc] init];
        
        return [mc autorelease];
    }
    
    - (void)dummyMethod
    {
        
    }
    
    @end

    这样一来,我们如果这么用:[[MyClass createMyObject] dummyMethod]会非常安全。因为createMyObject方法所返回的对象可确保是与MyClass类相兼容的。

    这里需要注意的是instancetype只能用作为返回类型,不允许作为参数或用于定义临时变量。

    我们下面将提供一个结合self特性与instancetype特性的工厂方法:

    @interface MyClass : NSObject
    
    + (instancetype)createMyObject;
    - (void)dummyMethod;
    
    @end
    
    @interface MySubClass : MyClass
    
    @end
    
    @implementation MyClass
    
    - (id)init
    {
        self = [super init];
        
        NSLog(@"Hello, world");
        
        return self;
    }
    
    + (instancetype)createMyObject
    {
        MyClass *mc = [[self alloc] init];
        
        return [mc autorelease];
    }
    
    - (void)dummyMethod
    {
    
    }
    
    @end
    
    @implementation MySubClass
    
    - (id)init
    {
        self = [super init];
        
        NSLog(@"Hi, world!");
        
        return self;
    }
    
    - (void)dummyMethod
    {
        NSLog(@"I am a child.");
    }
    
    @end

    你可以调用[[MySubClass createMyObject] dummyMethod],可以看看输出结果。


    此时,你会有个疑问,我直接用MyClass *myObj = [[MySubClass alloc] init];不也一样可以嘛,需要那么复杂吗?

    当然,C++、Java等编程语言都是这么做的。而Objective-C目前有两种状态,一种是MRC(Manual Reference Count),另一种是ARC(Auto Reference Count)。这两种模式对于实例创建而言是不一样的。前者创建完了之后,需要调用release,而后者则不需要。因此,我们通过上述讲解的通过类方法来创建autorelease对象来有效地屏蔽应用层接口的统一性问题。我们看到Apple自己在iOS7.0开始可用的框架都大量用了此种方法。这样,通过模版自动生成出来的代码不管是在MRC下还是在ARC下都能正常工作。

  • 相关阅读:
    Spark数据读取
    05、TypeScript 中的泛型
    04、TypeScript 中的接口
    03、TypeScript 中的类
    02、TypeScript 中的函数
    01、TypeScript 数据类型
    Vue-router 知识点
    什么是跨域?如何解决跨域问题
    工作中积累的问题、知识点总结100题(0-20)
    封装一个 Promise 对象。了解其原理
  • 原文地址:https://www.cnblogs.com/zenny-chen/p/3572146.html
Copyright © 2011-2022 走看看