swift初始化常见错误

作者: coderhlt | 来源:发表于2018-08-20 18:44 被阅读0次

    importUIKit

    前言:swift的初始化过程真的比oc的初始化难啊难,需要反反复复看。为了更好地理解、快速上手swift,记录一些常见的错误例子。

    错误一:存储属性没有被初始化

    • eg1:
    class Student{
    
        var name:String
    
    }
    
    

    报错:Class 'Student' has no initializers

    • eg2:
    class Student{
    
    var name:String
    
    init() {
    
    
    
      }
    
    }
    

    报错:Return from initializer without initializing all stored properties

    类和结构体在创建实例时,必须为所有存储型属性设置合适的初始值。存储型属性的值不能处于一个未知的状态,因此eg1和eg2报错都是因为属性没有被初始化造成的。我们可以在构造器中为存储型属性赋初值,也可以在定义属性时为其设置默认值。

    class student {
    
    var name:String
    
    init() {
    
    name = ""
    
      }
    
    }
    class student {
    
    var name = ""
    
    }
    

    错误二:在调用父类的初始化方法前,自身的存储属性未被初始化

    class Student:NSObject{
    
    var name:String
    
    override init() {
    
    super.init()
    
    self.name = ""
    
    }
    
    }
    

    报错:Property 'self.name' not initialized at super.init call

    指定构造器必须保证它所在类引入的所有属性都必须先初始化完成,之后才能将其它构造任务向上代理给父类中 的构造器。一个对象的内存只有在其所有存储型属性确定之后才能完全初始化。为了满足这一规则,指定构造器

    必须保证它所在类引入的属性在它往上代理之前先完成初始化。而例子中我们却刚好违背了这一原则,student的name属性还未初始化就调用了父类的初始化。

    纠正:

    Student:NSObject{
    
    var name:String
    
    override init() {
    
    self.name = ""
    
    super.init()//可以省略,系统会自动调用
    
    }
    
    }
    

    错误三:在调用父类的初始化方法前,自身的存储属性未被初始化并未调用其直接父类的的指定构造器

    • eg1:
     class student: NSObject {
    
          init(name:String) {
    
          super.init()
    
        }
    
      }
    
    

    不报错

    class view: UIView{
    
        init(name:String) {
    
        super.init()
    
      }
    
    

    报错:Must call a designated initializer of the superclass。

    也许这是你会想到oc的它们的自定义构造:

    @implementation student
    
    - (instancetype)initWithname:(NSString *)name{
    
    self = [super init];
    
    if (self) {
    
    }
    return  self;
    
    }
    @end
    
    @implementation view
    - (instancetype)initWithname:(NSString *)name{
    
    self=[super init];
    
    if (self) {
    
    }
    return self;
    
    }
    @end
    
    

    嗯,嗯oc这里的确没毛病。而swift就不一样了,swift的指定构造器必须调用其直接父类的的指定构造器。注意了是:“直接”(重要的强调三遍)父类的指定构造器。eg1中student的直接父类构造器就是super.init()没毛病,而eg2中的view的父类直接构造器不是super.init(),它是 super.init(frame: CGRECT)

    纠正:

      init(name:String, frame:CGRect) {
      super.init(frame: frame)
    }
      required init?(coder aDecoder: NSCoder) {
    
      fatalError("init(coder:) has not been implemented")
    
        }//自定义view必须写上这个方法,即时我们不从xib或storboard加载view,要不然编译会报错
    

    错误四:调用父类构造器之前访问了父类的属性

    class person{
    var age = 12
    }
    class student: person {
    var name = ""
    init(age:Int,name:String) {
    self.age = 11
    }
    }
    
    

    报错:'self' used in property access 'age' before 'super.init' call

    指定构造器必须先向上代理调用父类构造器,然后再为继承的属性设置新值。如果没这么做,指定构造器赋予的 新值将被父类中的构造器所覆盖。也就是在这个例子中,我们先访问了继承父类的age属性,系统后调用了super.init造成错误。

    纠正:

      class person{
    var age = 12
    }
    
    class student: person {
    var name = ""
    init(age:Int,name:String) {
    super.init()
    self.age = 11
    }
    }
    

    五给扩展类添加新的指定构造器或析构器

    extension UIBarButtonItem{
        init(age:String) {
    
        }
    
    }
    
    

    报错:Designated initializer cannot be declared in an extension

    扩展能为类添加新的便利构造器,但是它们不能为类添加新的指定构造器或析构器。指定构造器和析构器必须总是由原始的类实现来提供。因此在为分类增加扩展的方法,我们需要提供便利构造器。

    纠正:

    extension UIBarButtonItem{
    
    convenience init(age:String) {
    
    let btn = UIView()
    
    self.init(customView: btn)
    
      }
    
    }
    
    

    相关文章

      网友评论

        本文标题:swift初始化常见错误

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