iOS:繼承詳解

Apple

目錄
一,基本概念
二,優缺點
三,高耦合的示例
四,使用要點
五,使用場景
六,Super簡單介紹
七,替代方案
八,多繼承html

一,基本概念

繼承、封裝、多態是面向對象的三大支柱。OC只支持單繼承,父類能夠有多個子類,但子類有且僅有一個父類git

二,優缺點

優勢:代碼複用
缺點:高耦合github

三,高耦合的示例

看看Casa大神描述的場景編程

四,使用要點

1,父類只給子類提供服務,並不涉及子類的業務邏輯
2,層級關係明顯,功能劃分清晰,父類和子類互不干擾
3,父類的全部變化都須要在子類中體現,此時耦合已經成爲需求
4,不宜超過2層,第3層繼承是濫用的開端bash

5,做爲一個開發人員,有一個交流學習的圈子是很重要的。如今小編這邊有一個學習交流羣(810733363)。歡迎你們進入交流學習。學習


五,使用場景

1,繼承系統類庫,好比自定義UITableViewCell
2,把公共的屬性和方法放入父類中ui

@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系列中進行講解atom

1,在子類的init方法中必須調用[super init],由於在初始化子類以前必須先初始化父類spa

- (instancetype)init {
    self = [super init];
    if (self) {
    }
    return self;
}
複製代碼

2,若是父類的某個方法沒有實現,在子類的此方法中不能調用[super method],不然會crash3d

@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

// Man
@interface Man : NSObject <PersonProtocol>
@end

@implementation Man
- (void)eat {
    NSLog(@"man eat");
}
@end

// Woman
@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,消息轉發

消息轉發流程
  • 快速消息轉發
@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複製代碼

來源:本文爲第三方轉載,若有侵權請聯繫小編刪除。

相關文章
相關標籤/搜索