• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Swift的convenience&&designatedinit

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

http://www.th7.cn/Program/IOS/201603/789227.shtml

 

在 OC 中 init 方法是非常不安全的,没人能够保证 init 只被调用一次,也没有人保证在初始化方法调用以后实例的各个变量都完成初始化,甚至如果在初始化里使用属性进行设置的的话,还可能会造成各种问题。Swift 强化了 designated 初始化方法的地位。swift 中不加修饰的 init 方法都需要在方法中保证所有非 Optional 得实例变量被赋值初始化,而在子类中也强制(显示或隐式的)调用 super 版本的 designated 初始化,所以无论怎样被初始化的对象总是可以完成完整的初始化的。

class ClassA {   
    let numA: Int    
    // 不加修饰的 init 方法都需要在方法中保证所有非 Optional 得实例变量被赋值初始化
    init(num: Int) { 
        numA = num    
    }
}

class ClassB: ClassA {    
    let numB: Int    
    override init(num: Int) {       
        numB = num + 1  // 在 init 里我们可以对 let 的实例常量进行赋值,这是初始化方法的重要特点。正常情况下 let 声明的值是不可变的,无法被赋值,这对构建线程安全的 API 十分有用。而 init 只可能被调用一次,所以在 init 里我们可以为不变量进行赋值,而不会引起任何线程安全的问题        
        super.init(num: num)    
    }
}

 

与 designated 初始化方法啊对应的是在 init 前加上 convenience 关键字的初始化方法。这类方法只作为补充和提供使用上的方便。所有的 convenience 初始化方法都必须调用同一个类中的 designated 初始化完成设置,另外 convenience 的初始化方法是不能被子类重写或者是从子类中以 super 的方式被调用的。

class ClassAA {    
    let numA: Int    
    init(num: Int) {        
        numA = num    
    }    
    convenience init(bigNum: Bool) {        
        self.init(num: bigNum ? 10000 : 1) // 所有的 convenience 初始化方法都必须调用同一个类中的 designated 初始化完成设置    
    }
}

class ClassBB: ClassAA {    
    let numB: Int    
    override init(num: Int) {        
        numB = num + 1        
        super.init(num: num)    
    }
}

 

只要在子类中实现重写了父类 convenience 方法所需要的 init 方法的话,我们在子类中就可以使用父类的 convenience 初始化方法了。比如上面我们即使在 ClassBB 中没有 bigNum 版本的 convenience init(bigNum: Bool),我们仍然是可以是用这个方法来完成子类初始化的:

let anObj = ClassBB(bigNum: true)
print(anObj.numA, anObj.numB)

输出:10000和10001

 

总结:初始化方法永远遵循以下两个原则

1.初始化路径必须保证对象完全初始化,这可以通过调用本类型的 designated 初始化方法得到保证;

2.子类的 designated 初始化方法必须调用父类的 designated 方法,以保证父类也完成初始化。

 

  对于某些我们希望子类中一定实现的 designated 初始化方法,我们可以通过添加 required 关键字进行限制,强制子类对这个方法重写实现。这样做的最大的好处是可以保证依赖于某个 designated 初始化方法的 convenience 一直可以被使用。

下面的代码中如果希望初始化方法对于子类一定可用,就将 init(num: Int) 声明为必须。

class ClassAAA {    
    let numA: Int    
    required init(num: Int) {        
        numA = num    
    }    
    required convenience init(bigNum: Bool) {        
        self.init(num: bigNum ? 10000 : 1)    
    } 
}

class ClassBBB: ClassAAA {    
    let numB: Int    
    required init(num: Int) {        
        numB = num + 1        
        super.init(num: num)    
    }
}

let sencondObj = ClassBB(bigNum: true)
print(sencondObj.numA, sencondObj.numB)

输出:10000和10001

 

对于 convenience 的初始化方法也可以加上 required 以确保子类对其进行实现。


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Swift-Switch穿透发布时间:2022-07-13
下一篇:
Swift发送邮件和发短信发布时间:2022-07-13
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap