美文网首页
深入浅出Objective-C笔记(六)

深入浅出Objective-C笔记(六)

作者: 无聊的呆子 | 来源:发表于2015-11-19 22:07 被阅读15次

    类的继承(续)


    • 方法的覆盖(overriding)

    子类的方法若跟父类的方法名一样,则子类的方法会覆盖掉父类的方法,最终执行子类的方法。

    一个例子,只有print方法的子类和父类

    #import <Foundation/Foundation.h>
    
    @interface BaseClass : NSObject
    - (void) print;
    @end
    
    @implementation BaseClass
    - (void)print {
        NSLog(@"print in BaseClass");
    }
    
    @interface InheritClass : BaseClass
    - (void)print;
    @end
    
    @implementation InheritClass 
    - (void)print {
        NSLog(@"print in InheritClass");
    }
    
    int main(int argc, const char *argv[]) {
        @autoreleasepool {
            BaseClass *base = [ [BaseClass alloc] init ];
            InheritClass *inherit = [ [InheritClass alloc] init ];
            [base print];
            [inherit print];
        }
        return 0;
    }
    
    输出结果为: print in BaseClass
               print in InheritClass 
    
    • 如果出现方法的覆盖,但是我们又想要用父类的方法那怎么办?

    ** 用super关键字。**

    superself很像,都是对当前对象的引用(对自身的引用)。

    不一样的是,super会把当前的对象当做父类对象。

    举个例子:在上述代码中,加入一行[super print]即可

    int main(int argc, const char *argv[]) {
        @autoreleasepool {
            BaseClass *base = [ [BaseClass alloc] init ];
            InheritClass *inherit = [ [InheritClass alloc] init ];
            [base print];
            [inherit print];
            [super print];
        }
        return 0
    }
    
    输出结果是:print in BaseClass
              print in InheritClass
              print in BaseClass 
    
    • 两个关键字 idinstancetype

    e.g.

    #import <Foundation/Foundation.h>
    
    @interface A : NSObject
    + (A*)factoryMethod;//工厂方法可以创建自身类型的对象。工厂方法定义成一个类方法(加号开头)
                          //用来创建当前类的实例对象,所以返回类型是个指针(对象)
    - (void)methodA;//这个是实例方法
    @end
    
    @implementation A
    + (A*)factoryMethod {
        return [[A alloc] init];//工厂方法的实现(作用)就是返回一个生成的实例对象
    }
    
    - (void)methodA {
        NSLog(@"Call MethodA!");//一个简单的实例方法的实现,往控制台输出东西
    }
    @end
    
    @interface B : A
    - (void)methodB;
    @end
    
    @implementation B
    - (void)methodB {
        NSLog(@"Call MethodB!");
    }
    @end 
    
    int main(int argc, const char *argv[]) {
        @autoreleasepool {
            A *a = [A factoryMethod];//调用类A的工厂方法创建类A的实例a
            B *b = [B factoryMethod];//虽然B继承了A,但是这里调用B的工厂方法是有问题的
        }//类B的工厂方法返回值还是类A,因为在定义类A的工厂方法时把返回值写死了
        return 0;//在实现里也把返回值写死了,只能返回类A的实例对象
    }
    

    解决办法:在类A中对工厂方法的声明和实现都使用id类型

    @interface A : NSObject
    + (id)factoryMethod;
    -(void)methodA;
    @end
    
    @implementation A
    + (id)factoryMethod {
        return [[self  class] alloc] init];//注意这里,使用了[self class]这条消息 
    }
    - (void)methodA {
        NSLog(@"Call MethodA!");
    }
    @end
    

    使用id会有个问题,因为编译器不知道返回的具体类型,所以不能做静态语法检测。

    比如在main方法里写[[A factoryMethod] methodB],这其实是错的,因为类A根本就没有methodB ,但是却能编译通过了,因为编译器不知道工厂方法的返回值类型,所以不知道你返回的对象有没有methodB ,就默认通过了。

    解决办法:使用instancetype类型。它比较特殊,只能用做方法的返回值来用。** 它表示返回值是这个方法所在类的类型。**

    若用instancetype代替类A工厂方法的返回类型id

    @interface A : NSObject
    + (instancetype)factoryMethod;
    

    若还在main方法里写[[A factoryMethod] methodB],这时编译器就会报错了,因为instancetype表示了[A factoryMethod]的返回值为factoryMethod这个方法所在类的类型 ,即类A 。类A没有methodB,当然会报错。

    id虽然灵活,却可能瞒混编译器,隐藏一些bug,所以有时可以用instancetype代替 。instancetype有种硬点的意思。

    相关文章

      网友评论

          本文标题:深入浅出Objective-C笔记(六)

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