美文网首页Objective-C
iOS:继承详解

iOS:继承详解

作者: 码小菜 | 来源:发表于2019-09-27 20:58 被阅读0次
    风景

    目录
    一,基本概念
    二,优缺点
    三,高耦合的示例
    四,使用要点
    五,使用场景
    六,Super简单介绍
    七,替代方案
    八,多继承

    一,基本概念

    继承、封装、多态是面向对象的三大支柱。OC只支持单继承,父类可以有多个子类,但子类有且仅有一个父类

    二,优缺点

    优点:代码复用
    缺点:高耦合

    三,高耦合的示例

    看看Casa大神描述的场景

    四,使用要点

    1,父类只给子类提供服务,并不涉及子类的业务逻辑
    2,层级关系明显,功能划分清晰,父类和子类互不干扰
    3,父类的所有变化都需要在子类中体现,此时耦合已经成为需求
    4,不宜超过2层,第3层继承是滥用的开端

    五,使用场景

    1,继承系统类库,比如自定义UITableViewCell
    2,把公共的属性和方法放入父类中

    // Person
    @interface Person : NSObject
    @property (nonatomic, copy) NSString *name;
    - (void)eat;
    @end
    
    // Man
    @interface Man : Person
    @end
    
    @implementation Man
    - (void)eat {
        NSLog(@"man eat");
    }
    @end
    
    // Woman
    @interface Woman : Person
    @end
    
    @implementation Woman
    - (void)eat {
        NSLog(@"woman eat");
    }
    @end
    
    // 使用
    Man *man = [Man new];
    man.name = @"111";
    [man eat];
    
    Woman *woman = [Woman new];
    woman.name = @"222";
    [woman eat];
    
    六,Super简单介绍

    super的本质跟runtime有关,详细的放在runtime系列中进行讲解

    1,在子类的init方法中必须调用[super init],因为在初始化子类之前必须先初始化父类

    - (instancetype)init {
        self = [super init];
        if (self) {
        }
        return self;
    }
    

    2,如果父类的某个方法没有实现,在子类的此方法中不能调用[super method],否则会crash

    @implementation Person
    @end
    
    @implementation Man
    - (void)eat {
        [super eat]; // crash
        NSLog(@"man eat");
    }
    @end
    

    3,如果父类的某个方法实现了,在子类的此方法中看情况调用[super method],如果需要用到父类的代码就调用,如果不需要就不调用,直接覆盖即可

    @implementation Person
    - (void)eat {
        NSLog(@"person eat");
    }
    @end
    
    @implementation Man
    - (void)eat {
        [super eat];
        NSLog(@"man eat");
    }
    @end
    

    4,重写系统的方法一般都需要调用[super method],因为系统内部做了很多初始化的工作

    - (void)viewDidLoad {
        [super viewDidLoad];
    }
    

    5,在子类的某个方法中调用[super method],在父类该方法中的self其实是子类的对象

    @implementation Person
    - (NSString *)name {
        return @"111";
    }
    - (void)eat {
        NSLog(@"person %@ eat", self.name);
        NSLog(@"person: %@", self);
    }
    @end
    
    @implementation Man
    - (NSString *)name {
        return @"222";
    }
    - (void)eat {
        [super eat];
        NSLog(@"man %@ eat", self.name);
        NSLog(@"man: %@", self);
    }
    @end
    
    // 使用
    Man *man = [Man new];
    [man eat];
    
    // 打印
    person 222 eat // 不是111
    person: <Man: 0x6000012f2e90>  // 不是Person
    man 222 eat
    man: <Man: 0x6000012f2e90>
    
    七,替代方案

    如果想达到代码复用并且能够解耦的效果,可以考虑下列几种方案

    1,协议:把公共方法放入协议中(通常会放在父类中)

    @protocol PersonProtocol <NSObject>
    - (void)eat;
    @end
    
    @interface Man : NSObject <PersonProtocol>
    @end
    
    @implementation Man
    - (void)eat {
        NSLog(@"man eat");
    }
    @end
    
    @interface Woman : NSObject <PersonProtocol>
    @end
    
    @implementation Woman
    - (void)eat {
        NSLog(@"woman eat");
    }
    @end
    

    2,代理:自定义公共方法(通常把公共方法放入父类中,再在子类中自定义)

    @protocol PersonDelegate <NSObject>
    - (void)personStartEat;
    @end
    
    // Person
    @interface Person : NSObject
    @property (nonatomic, weak) id<PersonDelegate> delegate;
    - (void)eat;
    @end
    
    @implementation Person
    - (void)eat {
        if ([self.delegate respondsToSelector:@selector(personStartEat)]) {
            [self.delegate personStartEat];
        }
    }
    @end
    
    // 使用
    @interface ViewController () <PersonDelegate>
    @end
    
    @implementation ViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        Person *person = [Person new];
        person.delegate = self;
        [person eat];
    }
    
    - (void)personStartEat {
        NSLog(@"每个使用Person的类都可以自定义此方法");
    }
    @end
    

    3,组合:看看Casa大神是如何使用的

    4,AOP(面向切面编程):把每个控制器公共的操作抽取出来统一处理(通常会放在BaseViewController中)

    @implementation ViewControllerConfigure
    + (void)load {
        [ViewControllerConfigure sharedInstance];
    }
    + (instancetype)sharedInstance {
        static ViewControllerConfigure *_sharedInstance = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _sharedInstance = [[ViewControllerConfigure alloc] init];
        });
        return _sharedInstance;
    }
    - (instancetype)init {
        if (self = [super init]) {
            // 拦截所有控制器的viewDidLoad方法
            [UIViewController aspect_hookSelector:@selector(viewDidLoad)
                                      withOptions:AspectPositionAfter
                                       usingBlock:^(id<AspectInfo> aspectInfo) {
                                           [self viewDidLoad:aspectInfo.instance];
                                       }
                                            error:nil];
        }
        return self;
    }
    - (void)viewDidLoad:(UIViewController *)viewController {
        NSLog(@"可以在这里统一处理");
    }
    @end
    

    第三方库Aspects的地址

    八,多继承

    虽然OC不支持多继承,但可以通过下列几种方案间接的实现

    1,协议

    @protocol Father <NSObject>
    - (void)handsome;
    @end
    
    @protocol Mather <NSObject>
    - (void)beautiful;
    @end
    
    @interface Son : NSObject <Father, Mather>
    @end
    
    @implementation Son
    - (void)handsome {
        NSLog(@"帅气的");
    }
    - (void)beautiful {
        NSLog(@"美丽的");
    };
    @end
    

    2,组合

    @interface Father : NSObject
    - (void)handsome;
    @end
    
    @interface Mather : NSObject
    - (void)beautiful;
    @end
    
    // Son
    @interface Son : NSObject
    - (void)handsome;
    - (void)beautiful;
    @end
    
    @interface Son ()
    @property (nonatomic, strong) Father *father;
    @property (nonatomic, strong) Mather *mather;
    @end
    
    @implementation Son
    - (instancetype)init {
        self = [super init];
        if (self) {
            _father = [Father new];
            _mather = [Mather new];
        }
        return self;
    }
    - (void)handsome {
        [_father handsome];
    }
    - (void)beautiful {
        [_mather beautiful];
    }
    @end
    

    3,消息转发

    消息转发流程
    • 快速消息转发
    // Father
    @interface Father : NSObject
    - (void)handsome;
    @end
    
    @implementation Father
    - (void)handsome {
        NSLog(@"帅气的");
    }
    @end
    
    // Mather
    @interface Mather : NSObject
    - (void)beautiful;
    @end
    
    @implementation Mather
    - (void)beautiful {
        NSLog(@"美丽的");
    };
    @end
    
    // Son
    @interface Son : NSObject
    - (void)handsome;
    - (void)beautiful;
    @end
    
    @interface Son ()
    @property (nonatomic, strong) Father *father;
    @property (nonatomic, strong) Mather *mather;
    @end
    
    @implementation Son
    - (instancetype)init {
        self = [super init];
        if (self) {
            _father = [Father new];
            _mather = [Mather new];
        }
        return self;
    }
    // 告诉系统把消息转发给哪个对象
    - (id)forwardingTargetForSelector:(SEL)aSelector {
        if ([_father respondsToSelector:aSelector]) {
            return _father;
        } else if ([_mather respondsToSelector:aSelector]) {
            return _mather;
        }
        return nil;
    }
    @end
    
    // 使用
    Son *son = [Son new];
    [son handsome];
    [son beautiful];
    
    // 打印
    帅气的
    美丽的
    
    • 标准消息转发
    @implementation Son
    - (instancetype)init {
        self = [super init];
        if (self) {
            _father = [Father new];
            _mather = [Mather new];
        }
        return self;
    }
    // 先对方法重新签名
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
        NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
        if (signature == nil) {
            if ([_father respondsToSelector:aSelector]) {
                signature = [_father methodSignatureForSelector:aSelector];
            } else if ([_mather respondsToSelector:aSelector]) {
                signature = [_mather methodSignatureForSelector:aSelector];
            }
        }
        return signature;
    }
    // 再转发消息
    - (void)forwardInvocation:(NSInvocation *)anInvocation {
        SEL sel = [anInvocation selector];
        if ([_father respondsToSelector:sel]) {
            [anInvocation invokeWithTarget:_father];
        } else if ([_mather respondsToSelector:sel]) {
            [anInvocation invokeWithTarget:_mather];
        }
    }
    @end
    

    相关文章

      网友评论

        本文标题:iOS:继承详解

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