swift可以多继承吗 - CSDN
  • 我们都知道OC是不支持多继承的,这是因为消息机制名称查找发生在运行时而非编译时,很难解决个基类可能导致的二义性问题,那么如果我们想要一个类a同时继承类b和类c,我们要如何做才能达到我们想要的结果呢?...

    背景

    我们都知道OC是不支持多继承的,这是因为消息机制名称查找发生在运行时而非编译时,很难解决多个基类可能导致的二义性问题,那么如果我们想要一个类a同时继承类b和类c,我们要如何做才能达到我们想要的结果呢?我们创建三个类ClassA、ClassB、ClassC,A和B分别有两个方法run和walk,假设我们需要让C同时拥有run和walk方法,我们可以通过下面几种方法来达到我们想要的效果。

    • 组合

    在ClassC的.h或者.m文件中,声明ClassA和ClassB的实例,这样我们就可以通过调用A类和B类实例来执行run和walk方法

    @class ClassA,ClassB;
    @interface ClassC : NSObject
    @property (nonatomic,strong) ClassA *a;
    @property (nonatomic,strong) ClassB *b;
    - (void)sport;
    @end
    复制代码
    #import "ClassC.h"
    #import "ClassA.h"
    #import "ClassB.h"
    
    @implementation ClassC
    - (void)sport{
        [self.a run];
        [self.b walk];
    }
    @end
    复制代码
    • delegate和protocol

    将C类需要继承的方法以及属性在ClassA和ClassB中各自声明一份协议,C类遵守这两份协议,同时在C类中实现协议中的方法以及属性

    @protocol ClassADelegate
    - (void)run;
    @property (nonatomic,copy) NSString *runDistance;
    @end
    复制代码
    @protocol ClassBDelegate
    - (void)walk;
    @property (nonatomic,copy) NSString *walkDistance;
    @end
    复制代码
    #import "ClassC.h"
    #import "ClassA.h"
    #import "ClassB.h"
    
    @interface ClassC()<ClassADelegate,ClassBDelegate>
    
    @end
    
    @implementation ClassC
    - (void)sport{
        [self run];
        [self walk];
    }
    
    - (void)run{
        self.runDistance = @"10000";
        NSLog(@"今天跑了%@步",self.runDistance);
    }
    - (void)walk{
        self.walkDistance = @"5000";
        NSLog(@"今天走了%@步",self.walkDistance);
        
    }
    
    @synthesize walkDistance;
    @synthesize runDistance;
    
    @end
    复制代码
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        ClassC *c = [[ClassC alloc] init];
        [c sport];
        // Do any additional setup after loading the view, typically from a nib.
    }
    复制代码
    • 消息转发(快速转发和标准转发)

    当向某个对象发送消息,但runtime system在当前类以及父类中都找不到对应方法的实现时,runtime system并不会立即报错使程序崩溃,而是依次执行下列步骤

    流程如下

    1. 动态方法解析:向当前类发送resolveInstanceMethod: 信号,检查是否动态向该类添加了方法
    2. 快速消息转发:检查该类是否实现了 forwardingTargetForSelector: 方法,若实现了则调用这个方法,若该方法返回nil或者非self,则向该返回对象重新发送消息
    3. 标准消息转发:runtime发送methodSignatureForSelector:消息获取Selector对应的方法签名。返回值非空则通过forwardInvocation:转发消息,返回值为空则向当前对象发送doesNotRecognizeSelector:消息,程序崩溃退出.

    消息转发越到后面代价越大

    实现过程

    • 快速消息转发的实现方法很简单,只需要重写- (id)forwardingTargetForSelector:(SEL)aSelector方法就可以了,我们来用例子证明,还是拿上面的ClassA和ClassB,假设B有walk方法,而A没有,此时我需要也要有walk方法,这里我们有两种方式来实现

    1.强转类型

    - (void)viewDidLoad {
       [super viewDidLoad];
       ClassA *a = [[ClassA alloc] init];
       [(ClassB *)a walk];
       //[a run];
    }
    复制代码
    #import "ClassA.h"
    #import "ClassB.h"
    #import "ClassA+MyCategory.h"
    
    @implementation ClassA
    - (void)run{
       NSLog(@"跑步");
    }
    
    - (id)forwardingTargetForSelector:(SEL)aSelector{
       // 当然这里可以通过判断方法名来决定转发的对象
       //NSString *seletorName = NSStringFromSelector(aSelector);
       //if([seletorName isEqualToString : @"xxx"])
       ClassB *b = [[ClassB alloc] init];
       if([b respondsToSelector:aSelector]){
           return b;
       }
       return nil;
    }
    @end
    复制代码
    1. 增加Category
    #import "ClassA.h"
    @interface ClassA (MyCategory)
    - (void)walk;
    @end
    复制代码
    - (void)viewDidLoad {
       [super viewDidLoad];
       ClassA *a = [[ClassA alloc] init];
       [a walk];
    }
    复制代码

    通过运行发现都会执行- (id)forwardingTargetForSelector:(SEL)aSelector方法,然后再重新发送消息执行ClassB的walk方法

    • 标准消息转发需要重写 methodSignatureForSelector: 和 forwardInvocation: 两个方法
    #import "ClassA.h"
    #import "ClassB.h"
    #import "ClassA+MyCategory.h"
    
    @interface ClassA(){
       ClassB *_b;
    }
    @end
    
    @implementation ClassA
    
    - (id)init
    {
       self = [super init];
       if (self) {
           _b = [[ClassB alloc] init];
           
       }
       return self;
    }
    - (void)run{
       NSLog(@"跑步");
    }
    
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
       NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
       // 当然这里可以通过判断方法名来决定转发的对象
       //NSString *seletorName = NSStringFromSelector(aSelector);
       //if([seletorName isEqualToString : @"xxx"])
       //ClassB *b = [[ClassB alloc] init];
       if(signature == nil){
           signature = [_b methodSignatureForSelector:aSelector];
       }
       NSUInteger argCount = [signature numberOfArguments];
       for (NSInteger i=0; i<argCount; i++) {
             NSLog(@"%s" , [signature getArgumentTypeAtIndex:i]);
       }
       NSLog(@"returnType:%s ,returnLen:%ld" , [signature methodReturnType] , [signature methodReturnLength]);
       NSLog(@"signature:%@" , signature);
       return  signature;
    }
    - (void)forwardInvocation:(NSInvocation *)anInvocation{
       // 当然这里可以通过判断方法名来决定转发的对象
       //NSString *seletorName = NSStringFromSelector(aSelector);
       //if([seletorName isEqualToString : @"xxx"])
       SEL selector = [anInvocation selector];
       //ClassB *b = [[ClassB alloc] init];
       if([_b respondsToSelector:selector]){
           //这里如果没有响应,系统则会报错崩溃
           [anInvocation invokeWithTarget:_b];
       }
    }
    @end
    复制代码
    运行结果
    2018-01-04 10:32:34.288075+0800 MultipleInheritanceDemo[2006:407016] @
    2018-01-04 10:32:34.288303+0800 MultipleInheritanceDemo[2006:407016] :
    2018-01-04 10:32:34.288399+0800 MultipleInheritanceDemo[2006:407016] returnType:v ,returnLen:0
    2018-01-04 10:32:34.288592+0800 MultipleInheritanceDemo[2006:407016] signature:<NSMethodSignature: 0x60000047a540>
    2018-01-04 10:32:34.288887+0800 MultipleInheritanceDemo[2006:407016] 散步
    复制代码
    • 类别(category)

    类别也可以用来模拟多继承,比如给当前类添加方法,利用runTime来添加属性,方法不表,在前一篇文章Category与Extension有实现

    • NSProxy

    我们都知道NSObject是Objective-C中大部分类的基类。但不是很多人知道除了NSObject之外的另一个基类——NSProxy,苹果官方文档是这样描述的

    NSProxy is an abstract superclass defining an API for objects that act as
    stand-ins for other objects or for objects that don’t exist yet. Typically, a
    message to a proxy is forwarded to the real object or causes the proxy to
    load (or transform itself into) the real object. Subclasses of NSProxy can be
    used to implement transparent distributed messaging (for example,NSDistantObject) or for lazy instantiation of objects that are expensive to
    create...
    复制代码

    总的来说,NSProxy是一个虚类,你可以通过继承它,并重写这两个方法以实现消息转发到另一个实例

    - (void)forwardInvocation:(NSInvocation *)anInvocation;
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel;
    复制代码

    这里推荐一篇文章,写的非常详细明白点我点我

    总结

    好了以上就上关于如何实现iOS的“多继承”,大家还有其他的补充和建议可以留言。

    参考资料 念茜的博客

    展开全文
  • Swift 继承

    2019-06-24 06:35:57
    与其它面向对象语言一样,Swift 中的类也有继承特性。 一个类可以继承另一个类的方法、属性和下标。 当一个类继承其它类,继承类叫子类,被继承类叫做超类或父类。 在 Swift 三大数据结构中,只有类拥有继承的特性...

    前言

    • 与其它面向对象语言一样,Swift 中的类也有继承特性。

      • 一个类可以继承另一个类的方法、属性和下标。
      • 当一个类继承其它类,继承类叫子类,被继承类叫做超类或父类。
      • 在 Swift 三大数据结构中,只有类拥有继承的特性,结构体和枚举是没有的。
      • 在 Swift 中子类可以访问和调用父类中的属性、方法和下标,并且可以h使用关键字 override 来重写。

    1、Swift 继承

    • Swift 语言中使用 : 符号来表示继承的关系,在定义类时的类名后加上 : 符号和基类名,表示当前定义的类继承了该基类。

      • 继承后子类自动就获得了父类的相关属性和方法。
      • self 指向的是当前对象,而对于超类属性和方法的访问,如果继承自父类或祖先类的,就可以用 self 来访问。但在初始化方法中,我们调用父类的 init 方法时,只能用 super 来指向和访问。

    2、重写(覆盖)

    • 如果子类和父类的方法、属性重名,有一个专门的术语叫覆盖或者重写。

      • 我们可以在子类中写上同名,同样参数和返回值的方法,以重写父类中的相应方法。
      • 参数一定要相同,否则就是重载,而不是重写或者覆盖。
      • 可以将一个继承来的只读属性重写为一个只读属性,只需在重写版本的属性里提供 get 方法和 set 方法即可。
      • 不可将一个继承来的读写属性重写为一个只读属性。
      • 可以在属性重写中为一个继承来的属性添加属性观察者。
    • 重写方法或参数时需在方法的 func 前和属性的类型 var 前加上 override 关键字。

      /// 父类
      class Transport {
      
          var scope = ""
      
          func move() {
              print("move")
          }
      }   
      /// 子类
      class Car: Transport {
      
          // 重写属性
          override var scope: String {
              didSet {
                  print("Car scope")
              }
          }
      
          // 重写方法
          override func move() {
              print("Car move")
          }
      
          // 调用父类中的方法
          func superMove() {
              super.move()
          }
      }
    • 可以在不希望被子类重写的方法、属性或下标前面写上关键字 final,以防止他们被子类重写。甚至可以在类的定义前写上 final,使整个类都不能被继承。

      class Transport {
      
          var scope = ""
      
          // 使得 move 方法不能被重写
          final func move() {
              print("move")    
          }
      }
      // 使得 Transport 类不能被继承
      final class Transport {
      
          var scope = ""
      
          func move() {
              print("move")
          }
      }

    转载于:https://www.cnblogs.com/QianChia/p/8652317.html

    展开全文
  • 面向对象编程语言的一个重要的功能就是继承,继承的主要描述就是类与类的关系,通过继承可以在不必重写类的情况下,使用原有类的功能和进行扩展 继承的实现 属性的继承 方法的继承 属性观察器的继承 下标脚本的继承...

    Swift 继承:

    • 面向对象编程语言的一个重要的功能就是继承,继承的主要描述就是类与类的关系,通过继承可以在不必重写类的情况下,使用原有类的功能和进行扩展

    继承的实现

    • 属性的继承
    • 方法的继承
    • 属性观察器的继承
    • 下标脚本的继承(代码中没有写)

    代码示例

    class Person {
        //存储属性
        var name = "老王"
        //类型属性
        static var age = 18
        //计算属性
        var description : String {
            return "我的姓名\(name),年龄:\(Person.age)"
        }
    
        //属性观察器
        var height : Int = 180 {
    
            willSet {
    
            }
            didSet {
               Person.age = 20
               print("-----\(Person.age)")
            }
        }
    
        //方法
        func run() {
            print("正在跑")
        }
        static func play() {
            print("玩篮球")
        }
    }
    
    class Stu : Person {
    
    }
    //属性的继承
    Stu.age
    //方法的继承
    Stu.play()
    
    let stu1 = Stu()
    //属性的继承
    stu1.name
    stu1.description
    //属性观察器的继承
    stu1.height = 160
    //方法的继承
    stu1.run()
    
    

    重写的实现

    • 属性的重写
    • 方法的重写
    • 属性观察器的重写
    • 下标脚本的重写(代码中没有写)

    代码示例

    class Teacher {
        //存储属性
        var name = "老王"
        //类型属性
        class var age : Int {
            return 18
        }
        //计算属性
        var description : String {
            return "我的姓名\(name),年龄:\(Person.age)"
        }
    
        //属性观察器
        var height : Int = 180 {
    
            willSet {
    
            }
            didSet {
                Person.age = 20
                print("-----\(Person.age)")
            }
        }
    
        //方法
        func run() {
            print("正在跑")
        }
        class func play() {
            print("玩篮球")
        }
    }
    
    class tech : Teacher {
    
        var tempName : String = ""
        //重写存储属性
        override var name: String {
    
            get {
                return self.tempName
            }
            set {
                self.tempName = newValue
            }
        }
        //重写计算属性
        override var description : String {
    
            return "我的姓名\(name)"
        }
        //重写类型属性
        override class var age : Int {
            return 23
        }
        //重写属性观察
        override var height : Int {
    
            willSet {
    
            }
            didSet {
                Person.age = 20
                print("-----\(Person.age)")
            }
        }
    
        //重写实例方法
        override func run() {
            print("跑步")
        }
        //从写类型方法
        override class func play() {
            print("玩排球")
        }
    
    }
    
    
    
    tech.play()
    tech.age
    
    
    let t1 = tech()
    t1.run()
    t1.height = 200
    t1.name = "老王"
    t1.description
    
    展开全文
  • swift初始化方法调用顺序

    在《Swift Programming Language》中, 描述了Swift Class实例的初始化调用有经历两个阶段。

    结合下面的代码记录之。

    class Person {
    
        var name: String
        var age: Int
        var blog = ""
    
        init(name: String, age: Int) {
            self.name = name
            self.age = age
        }
    }
    
    
    class Programmer: Person {
        
        var preferredSkill: String
    
        override init(name: String, age: Int) {
            self.preferredSkill = "Swift"
            super.init(name: name, age: age)
            self.blog = "CSDN"
        }
    
    }
    
    var programmer = Programmer(name: "Ray", age: 24)
    println(programmer.preferredSkill)


    第一个阶段:

    1.  子类Programmer的init()方法被调用

    2.  Programmer类新的实例的占用内存被分配完毕,但未被初始化(allocated but not initialized)

    3.  Programmer类初始化由自己引入的stored property的初始值, 这些stored property的内存现在处于initialized的状态 (perferredSkill = “Swift”)

    4.  Programmer类调用直接父类Person类的init()方法, Person类初始化由自己引入的stored property的初始值 (name="Ray", age=24, blog="")

    5.  如果Person类还有父类,重复3-4步

    6.  现在新Programmer实例的所有stored property都处于initialized状态了


    第二个阶段:

    1.  现在可以获取并使用self属性了

    2. 从Person类开始, 检查有需要改变的值么?没有, 寻找Person的直接子类Programmer类

    3. 改变blog的值到“CSDN” (blog = "CSDN")


    总结:

    在构造子类的实例时,初始化方法调用分为两个阶段,第一个阶段向上初始化所有的属性,第二个阶段根据需要向下改变属性的值


    展开全文
  • 实现多继承的4种方式

    2019-07-09 10:07:06
    实现多继承的4种方式 继承的目的就是:能实现调用父类的方法、属性 ...二:protocol,协议是支持多继承的(一个类可以实现实现个协议) 三:类别 四:消息转发机制 转载于:https://www.cnblogs.com/shidaying/p...
  • 二十八 Swift3.0之 继承

    2017-04-19 08:45:24
    /* 继承语法 继承是面向对象最显著的一个特性, 继承是从已经有的类中派生出新的类 新的类能够继承已有类的属性和方法, 并能扩展新的能力 ...注意:Swift和OC一样没有多继承 */class Man { var name:S
  • swift可以继承NSObject

    千次阅读 2015-10-23 09:41:00
    swift中,一个对象可以继承自NSObject - 继续自NSObject 可以使用KVC方法给属性设置数值 =》如果是模型对象,最好还是使用NSObject - 如果对象,没有属性,或者不依赖KVC , 可以建立一个没有父类的对象!, ...
  • swift 继承

    2017-03-14 09:44:21
    一个类可以继承另一个类的方法,属性和其他特性。当一个雷继承其他类的时候,继承类叫子类,被继承类叫超类。在swift中,继承是区分类与其他类型的一个基本特征。 在swift中,类可以调用和访问超类的方法,属性和...
  • Swift继承、重写

    2017-01-08 20:55:14
    继承、重写 /* 1、继承语法 继承是面向对象最显著的一个特征。... swift继承语法: class ChildClass:FatherClass{ } 继承优点:代码重用 继承缺点:增加程序耦合度,父类改变会影响子类 swift没有继承(单继
  • [Swift]继承

    千次阅读 2014-12-01 16:31:01
    1. Swift继承的基本概况:  1) 只有类能继承其它类型都不支持继承,包括基本类型、集合、结构体、枚举;  2) 和Java一样只支持单继承不支持继承,Swift的继承是由协议实现的(和Java的接口很像,可以通过遵守...
  • Swift笔记:继承

    2016-04-19 15:52:22
    一个类可以继承(inherit)另一个类的方法(methods),属性(properties)和其它特性。当一个类继承其它类时,继承类叫子类(subclass),被继承类叫超类(或父类,superclass)。在 Swift 中,继承是区分「类」与...
  • Swift- 继承

    2018-06-20 08:41:16
    //Swift 中的 Class 可以继承父类的方法, 属性和其它特征.继承是 Class 区别于其它类型的一个主要特点 //1. 定义一个基类(Base Class) //没有父类的类称为基类 class Vehicle { var currentSpeed = 0.0 var ...
  • Swift继承/协议/泛型

    2020-06-21 11:58:37
    Swift 中,类可以调用和访问超类的方法,属性和下标脚本,并且可以重写它们。 语法: class SomeClass: SomeSuperclass { // 类的定义 } 子类可以通过继承来的实例方法,类方法,实例属性,或下标脚本来实现...
  • /*  * 继承(inherit)  单向关系  1、定义:某个类通过继承语法而获取另一个类的属性和方法。  2、最大好处:实现代码复用(父类中的属性和方法可以被子类... 4、Swift中只有单继承(通过“扩展”和“协议”实
  • Swift中,继承只能发生在类身上,结构体和枚举是不能够被继承的。一个类可以继承另一个类的方法、属性和下标。当一个类继承自另一个类时,这个类就被称之为子类,而被继承的类则被称之为父类(超类)。子类可以重写...
  • 【Swift初见】Swift继承

    千次阅读 2015-03-09 16:09:54
    对于继承这个名字大家应该都不陌生,在swift中也是一样,swift中的一个类可以继承另一个类的方法,属性和其他特性。当一个类继承其他类时,继承类叫做子类,被继承的类叫做父类,在swift继承是区分类与其他类型的...
  • swift继承

    2018-12-18 10:20:46
    2.13 继承 本页包含内容: 定义一个基类 子类生成 重写 防止重写 一个类可以继承另一个类的方法,属性和其它特性。当一个类继承其它类时,继承类叫子类,被继承类叫超类(或父类)。在 Swift 中,继承是区分「...
  • swift面向对象之多态与继承

    千次阅读 2016-04-27 09:15:50
    swift面向对象之多态与继承 1.多态 运行时多态 运行时多态的要点 ...继承可以用于类而不能用于结构体和枚举,继承也可用于协议 swift中不能使用继承,oc中也是 父类的计算属性可以被子类所
  • 构造方法内容会一些,涉及Swift中构造的一些规则与概念。这次写了7个Person来复习,外加名人XiaoMing。 Mark:Playground真是个好东西,特别练习写Swift时,实时显示真是大赞! 一、继承与重写, 防止重写 1.1 ...
  • swift之类的继承

    2016-06-16 13:51:37
    swift之类的继承 继承(Inheritance) 综述:一个类可以继承(inherit)另一个类的方法(methods),属性(properties)和其它特性。当一个类继承其它类时,继承类叫子类(subclass),被继承类叫超类(或父类,...
1 2 3 4 5 ... 20
收藏数 15,246
精华内容 6,098
热门标签
关键字:

swift可以多继承吗