• 类别、延展、继承


    Objective-C中继承和类别的比较:category&Inherit   

     
     
    • 分享类型:应用开发相关

     
    在Objective-C中,给一个类扩展一个其它方法,有两种实现方式:类别和继承。
    1.继承Inherit
    这个是面向对象语言都有的一个特性,子类会继承父类的方法和属性。
    对于以下情况,无法使用类别,必须使用继承。
    1)新扩展的方法与原方法同名,但是还需要使用父类的实现。因为使用类别,会覆盖原类的实现,无法访问到原来的方法。
    2)扩展类的属性,这个类别无法做到。
    示例代码:
    1
    2
    3
    4
    5
    6
    7
    8
    //  ViewControllerEx.h
    @interface ViewControllerEx : UIViewController
    //自己需要添加的方法
    @end
    // ViewControllerEx.m
    @implementation ViewControllerEx
    // 方法的实现
    @end


    2.类别category
    这是Objective-C语言的一个特性,可以在不改变类名和原来类的实现的前提下,实现对类的方法扩展。
    以下两种方式最后使用类别。
    1)针对系统提供的一些类,例如:NSString,NSArray,NSNumber等类,系统本身不提倡使用继承去扩展方法,因为这些类内部实现对继承有所限制,所以最后使用类别来进行方法扩展。
    2)类别支持开发人员针对自己构建的类,把相关的方法分组到多个单独的文件中,对于大型而复杂的类,这有助于提高可维护性,并简化单个源文件的管理。
    示例代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 这里有一个约定俗成的规定,类别文件命名时,是原类名+扩展标识名
    //  NSString+ex.h
    @interface NSString (ex)
    // 扩展的类回别方法
    @end
    //  NSString+ex.m
    @implementation NSString (ex)
    // 方法的实现
    @end



    原文地址:[url]http://bluevt.org/?p=183[/url] 

    ==========================================

    一 、类目: 为已存在的类添加新的方法。但是不能添加实例变量。

            应用:1、对现有的类进行扩展,如:系统中的类,在类目中增加的方法会被子类继承,而且在运行时跟其他的方法没有区别。

                           2、作为子类的替代方式,不需要定义和使用一个子类,可以通过类目直接向已有的类里增加方法。

                           3、对类中的方法进行归类,利用catigory把一个庞大的类划分为小块来分别进行开发,从而更好地对类中的方法进行更新和维护。

                           4、和普通接口有所区别的是,在Category的实现文件中的实例方法只要你不去调用它你可以不用实现所有声明的所有方法。

             局限性: 1、无法向类目中添加新的实例变量。

                               2、类目中的方法具有更高的优先级,若在类目中覆盖原始类的方法(重载)。会引起super消息的无效,因此,一般不要覆盖现有类中的方法。

                                     如果确实要重载,那就通过继承创建子类来实现。

             命名方式:类名+扩展方法,如“UIAlertView+AFNetworking”。类目的接口声明与类的定义十分相似,但类目不继承父类,只需要带有一个括号,表明该类目的主要用                                  途。

             在AFNetworking中有这样一个类目、实现附带alterview 的网络请求。 

             例:UIAlertView+AFNetworking.h文件中

    <span style="font-family:System;font-size:12px;">#import <Foundation/Foundation.h>@interface UIAlertView (AFNetworking)+ (void)showAlertViewForTaskWithErrorOnCompletion:(NSURLSessionTask *)task delegate:(id)delegate;</span>

              UIAlertView+AFNetworking.m文件中

    <span style="font-family:System;font-size:12px;">#import "UIAlertView+AFNetworking.h"@implementation UIAlertView (AFNetworking)+ (void)showAlertViewForTaskWithErrorOnCompletion:(NSURLSessionTask *)task delegate:(id)delegate{    [self showAlertViewForTaskWithErrorOnCompletion:task delegate:delegate cancelButtonTitle:NSLocalizedStringFromTable(@"Dismiss", @"AFNetworking", @"UIAlertView Cancel Button Title") otherButtonTitles:nil, nil];}</span><span style="font-size:12px;font-family: 宋体, 'Arial Narrow', arial, serif;"></span>

    二、延展:延展的作用就是定义自己的私有方法。

                  形式和类目相同,不用新创建文件,延展中定义的方法在类本身的@implementation代码区域中进行实现。

                         当在定义延展的时候不提供类目名时,延展中定义的方法既被视为“必须实现”的API在这种情况下,如果方法没有实现代码,那么编译器会报警告,这个时候方法的实现就一定要出现在类主体的@implementation代码块中了。

    ==========================================

     

    Objective C实现多继承!

    分类: Objective-C

            我们都知道objective C不能像C++一样支持多继承,但是在OC的使用经常会碰到需要使用多继承的情况。例如,ClassA中有methodA,ClassB中methodB,而现在需要使用这两个类中的方法。如何按照C++的编程思路,毫无疑问采用多继承就搞定了,在OC就需要动动脑子了。

            其实我们在学习设计模式的时候知道,多继承的效率不高,而且采用组合的模式可以完全代替继承模式。那么,这种思路完全可以用在OC中实现多继承(或许OC抛弃多继承,就是强迫我们使用更高效的组合设计模式吧!)。下面用实际的代码来表示组合如何来代替多继承。

           现在ClassC需要继承ClassA中methodA、ClassB中methodB,具体的代码实现为:

    //定义ClassA以及其methodA

    @interface ClassA : NSObject {
    }

    -(void)methodA;

    @end
    //定义ClassB以及其methodB
    @interface ClassB : NSObject {
    }

    -(void)methodB;

    @end
    //定义ClassC以及其需要的methodA,methodB
    @interface ClassC : NSObject {
      ClassA *a;
      ClassB *b;
    }

    -(id)initWithA:(ClassA *)A b:(ClassB *)B;

    -(void)methodA;
    -(void)methodB;

    @end

    //注意在ClassC的实现

    @implementation  ClassC

    -(id)initWithA:(ClassA *)A b:(ClassB *)B{

           a=[[ClassA alloc] initWithClassA: A];//[A copy];

           b=[[ClassB alloc] initWithClassB: B];//[B copy];

    }

    -(void)methodA{

          [a methodA];

    }
    -(void)methodB{

          [b methodB];

    }

    上面是采用组合的方式实现了多继承的功能,解决了OC不能多继承的语法。那么还有其他的方式来实现多继承吗?

    虽然OC在语法上禁止类使用多继承,但是在协议的遵守上却允许使用多继承。所以可以用协议来实现多继承。但是协议只能提供接口,而没有提供实现方式,如果只是想多继承基类的接口,那么遵守多协议无疑是最好的方法,而既需要多继承接口,又要多继承其实现,那么协议是无能为力了。多协议遵守比较简单,具体的实现方式这里就不讲了!


    =========================================================

    OC下的多继承(一)

      (2013-11-05 10:33:29)
    标签: 

    object-c下的多继承

     

    it

    分类: object-C



        我们知道object-C是在C语言的基础上添加了面向对象功能,相比于同样是对C语言进行扩展的C++,object-C更加简单,也更容易上手,但凡事必有利弊,作为编程语言,逻辑复杂也代表着其功能强大,例如C++中支持的多继承在我们object-C是不被支持的,那么object-C是否就真的抛弃多继承的逻辑设计了呢?答案是否定的,这里我们通过协议来实现类似C++中的多继承。OC下的多继承(一)

    由上图,我们有类ClassA、ClassB、ClassC及类中分别有方法a{}、b{}、c{},我们希望通过类C继承A和B,C的对象就可以使用a、b、c方法了。例如:

    ClassC *cObject = [[ClassC alloc] init];
           [cObject a];

           [cObject b];

           [cObject c];

    由于Objective-C在语法上禁止类使用多继承,所以我们ClassC无法直接继承ClassA和ClassB,但是在协议的遵守上却允许使用多继承。所以我们分享在ClassA和ClassB中定义协议,协议方法分别为a{}、b{},代码如下:

    1、ClassA.h内容

    @interface ClassA : NSObject

    @end

    @protocol ClassAProtocol <NSObject>

    -(void)a;

    @end

    2、ClassB.h内容

    @interface ClassB : NSObject

    @end

    @protocol ClassBProtocol <NSObject>

    -(void)b;

    @end

    3、ClassC.h内容(引用ClassAProtocol和ClassBProtocol 协议)

    OC下的多继承(一)

    此处我只定义一个成员方法c。

    而我在ClassC.m中的补充完善ClassAprotocol和ClassBProtocol中的a{}和b{}方法,详见下图

    OC下的多继承(一)

    4、当我用ClassC实例如一个对象cObject时,cObject就可以调动a{}和b{}方法,如下图:

    OC下的多继承(一)

    总结:类C虽然不能直接继承类A和类B,但我们可以通过继承两个类中的协议,以此来继承协议中的方法。

    ===============================================

    IOS中多重继承实现的折中方法

    发表于2年前(2013-11-10 23:50)   阅读(3084) | 评论(4) 28人收藏此文章, 我要收藏
    0

    9月19日成都 OSC 源创会正在报名,送机械键盘和开源无码内裤  


    我们知道OC是不支持多重继承的,那么我们希望ClassA的某些子类在某种情况下又能调用ClassB中的方法该这么办呢,有人说使用Protocal啊,那么你会发现,当你想增加一个方法的调用时,还是需要到ClassA和ClassB中去维护两份代码。而且你必须要修改ClassA和ClassB去conform 你的protocal。

    我们希望在不污染ClassA 和 ClassB的基础上使得ClassA的子类能够同时拥有ClassA和ClassB的方法(MethodA和MethodB),我认为category更适合这样的情景。

    首先ClassA

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @interface GTClassA : NSObject
    - (void)methodA;
    @end
     
    @implementation GTClassA
    - (void)methodA
    {
        NSLog(@"this is methodA");
    }
     
     
    @end
    然后是ClassB 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @interface GTClassB : NSObject
    - (void)methodB;
    @end
     
    @implementation GTClassB
    - (void)methodB
    {
        NSLog(@"this is methodB");
    }
     
    - (void)dealloc
    {
        NSLog(@"dealloc in %@",[self class]);
        [super dealloc];
    }
    @end
    我们将采用的方法是 构建一个ClassA的Category的方式,但这种方式有一个缺点,不能定义成员变量。如果MethodB中的方法需要回调,那么我们需要保持一个ClassB的Instance,但何时释放不造成内层泄露就成了问题,那先看完不需要回调的实现,我们再讨论吧: 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    //  Created by Guangtao Li on 13-11-10.
    //  Copyright (c) 2013年 Guangtao Li. All rights reserved.
    //
     
    #import "GTClassA.h"
    @interface GTClassA (ClassBInheritance)
    @end
     
    //  Created by Guangtao Li on 13-11-10.
    //  Copyright (c) 2013年 Guangtao Li. All rights reserved.
    //
    #import "GTClassA+ClassBInheritance.h"
    #import "GTClassB.h"
     
    @implementation GTClassA (ClassBInheritance)
    -(void)forwardInvocation:(NSInvocation *)anInvocation{
        if([self respondsToSelector:[anInvocation selector]]){
            [anInvocation invokeWithTarget:self];
        }else{
            GTClassB *classBInstance = [[GTClassB alloc] init];
            [anInvocation invokeWithTarget:classBInstance];
            [classBInstance release];//立刻释放了
        }
    }
     
    - (NSMethodSignature*)methodSignatureForSelector:(SEL)selector
    {
        NSMethodSignature* signature = [super methodSignatureForSelector:selector];
        if (!signature) {
            signature = [GTClassB instanceMethodSignatureForSelector:selector];
        }
        return signature;
    }
     
    -(BOOL)conformsToProtocol:(Protocol *)aProtocol{
        if([GTClassB conformsToProtocol:aProtocol] || [super conformsToProtocol:aProtocol]){
            return YES;
        }
        return NO;
    }

    GTClassA (ClassBInheritance):
    以上代码我们可以看到,由于没有能存放ClassB实例的变量,classB调用方法后就释放了。那么如果需要保留ClassB的实例,等ClassB调用dealloc 时再释放可不可以呢?
    我们可以用到 Associative References,在OC 的runtime 中去添加property了。 
    http://oleb.net/blog/2011/05/faking-ivars-in-objc-categories-with-associative-references/
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    //  GTClassA+ClassBInheritance.h
    //  MultipleInheritanceTest
    //
    //  Created by Guangtao Li on 13-11-10.
    //  Copyright (c) 2013年 Guangtao Li. All rights reserved.
    //
     
    #import "GTClassA.h"
    @class GTClassB;
    @interface GTClassA (ClassBInheritance)
    @property (nonatomic,retain) GTClassB *classBInstance;
    @end
     
    //
    //  GTClassA+ClassBInheritance.m
    //  MultipleInheritanceTest
    //
    //  Created by Guangtao Li on 13-11-10.
    //  Copyright (c) 2013年 Guangtao Li. All rights reserved.
    //
    #import <objc/runtime.h>
    #import "GTClassA+ClassBInheritance.h"
    #import "GTClassB.h"
    static char const * const ClassBInstanceKey = "ClassBInstanceKey";
     
     
    @implementation GTClassA (ClassBInheritance)
    @dynamic classBInstance;
    -(void)forwardInvocation:(NSInvocation *)anInvocation{
        if([self respondsToSelector:[anInvocation selector]]){
            [anInvocation invokeWithTarget:self];
        }else{
            if (self.classBInstance == nil) {
                self.classBInstance = [[GTClassB alloc] init];
                [self.classBInstance release];
            }
            [anInvocation invokeWithTarget:self.classBInstance];
     
        }
    }
     
    - (NSMethodSignature*)methodSignatureForSelector:(SEL)selector
    {
        NSMethodSignature* signature = [super methodSignatureForSelector:selector];
        if (!signature) {
            signature = [GTClassB instanceMethodSignatureForSelector:selector];
        }
        return signature;
    }
     
    -(BOOL)conformsToProtocol:(Protocol *)aProtocol{
        if([GTClassB conformsToProtocol:aProtocol] || [super conformsToProtocol:aProtocol]){
            return YES;
        }
        return NO;
    }
     
    - (GTClassB *)classBInstance {
        return objc_getAssociatedObject(self, ClassBInstanceKey);
    }
     
    - (void)setClassBInstance:(GTClassB *)newClassBInstance {
        objc_setAssociatedObject(self, ClassBInstanceKey, newClassBInstance, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    @end

    但是新的问题是这个property何时释放呢?如果我们在category中加入 dealloc如下,将会报错,因为category中的dealloc会覆盖原有的dealloc。其实不用担心,Associated Object 有个特点,当ClassA调用dealloc时将会自动release。所以我们什么都不用做就好啦。。。
    1
    2
    3
    4
    5
    6
    - (void)dealloc
    {
        NSLog(@"dealloc in %@",[self class]);
        [self.classBInstance release];
        [super dealloc];
    }
    ========================================================

  • 相关阅读:
    【刷题】洛谷 P3808 【模板】AC自动机(简单版)
    【刷题】BZOJ 3172 [Tjoi2013]单词
    【刷题】BZOJ 2434 [Noi2011]阿狸的打字机
    【刷题】BZOJ 1211 [HNOI2004]树的计数
    【刷题】BZOJ 1195 [HNOI2006]最短母串
    【刷题】BZOJ 1095 [ZJOI2007]Hide 捉迷藏
    【刷题】BZOJ 1030 [JSOI2007]文本生成器
    【刷题】BZOJ 3926 [Zjoi2015]诸神眷顾的幻想乡
    【刷题】BZOJ 2780 [Spoj]8093 Sevenk Love Oimaster
    【刷题】BZOJ 2753 [SCOI2012]滑雪与时间胶囊
  • 原文地址:https://www.cnblogs.com/dexjay/p/4781347.html
Copyright © 2020-2023  润新知