IOS开发者学习笔记Swift一步步学习

swift初始化常见错误

2018-08-20  本文已影响0人  coderhlt

importUIKit

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

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

class Student{

    var name:String

}

报错:Class 'Student' has no initializers

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()//可以省略,系统会自动调用

}

}

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

 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)

  }

}

上一篇下一篇

猜你喜欢

热点阅读