tre*_*son 81

标准init:

指定的初始值设定项是类的主要初始值设定项.指定的初始化程序完全初始化该类引入的所有属性,并调用适当的超类初始化程序以继续超类链的初始化过程.

convenience init:

便利初始化程序是次要的,支持类的初始化程序.您可以定义一个便捷初始值设定项,以便从与便捷初始化程序相同的类中调用指定的初始值设定项,并将某些指定的初始值设定项参数设置为默认值.您还可以定义一个便捷初始值设定项,以便为特定用例或输入值类型创建该类的实例.

根据Swift文档

基本上所有这一切都意味着你使用一个方便的初始化程序来更快,更"方便"地调用指定的初始化程序.因此,便利初始化程序需要使用self.init而不是像在super.init指定初始化程序的覆盖中看到的那样.

伪代码示例:

init(param1, param2, param3, ... , paramN) {
     // code
}

// can call this initializer and only enter one parameter,
// set the rest as defaults
convenience init(myParamN) {
     self.init(defaultParam1, defaultParam2, defaultParam3, ... , myParamN)
}
Run Code Online (Sandbox Code Playgroud)

我在创建自定义视图时使用了很多这样的视图,并且使用主要是默认值的长初始化程序.文档比我更好地解释,检查出来!

  • 为什么不使用默认值 (9认同)

Mag*_*ios 53

当你有一些具有很多属性的类时会使用便利初始化程序,这使得总是用所有变量初始化机智有点"痛苦",所以你使用便利初始化程序做的是你只需传递一些变量来初始化对象,并为其余部分分配默认值.Ray Wenderlich网站上有一个非常好的视频,不确定它是否免费,因为我有一个付费帐户.这是一个例子,你可以看到,而不是用所有这些变量初始化我的对象我只是给它一个标题.

struct Scene {
  var minutes = 0
}

class Movie {
  var title: String
  var author: String
  var date: Int
  var scenes: [Scene]

  init(title: String, author: String, date: Int) {
    self.title = title
    self.author = author
    self.date = date
    scenes = [Scene]()
  }

  convenience init(title:String) {
    self.init(title:title, author: "Unknown", date:2016)
  }

  func addPage(page: Scene) {
    scenes.append(page)
  }
}


var myMovie = Movie(title: "my title") // Using convenicence initializer
var otherMovie = Movie(title: "My Title", author: "My Author", date: 12) // Using a long normal initializer
Run Code Online (Sandbox Code Playgroud)

  • 我们还可以使用具有默认值author的init()和date参数作为`init(title:String,author:String =“ Unknown”,date:Int = 2016){self.title =标题self.author =作者self。日期=日期场景= [Scene]()}`那么为什么我们需要方便的初始化方法? (4认同)
  • 好例子。这使概念很明确。谢谢。 (2认同)

dir*_*nee 11

这是一个简单的例子,取自Apple Developer门户网站.

基本上,指定的初始化程序是init(name: String),它确保初始化所有存储的属性.

init()方便初始化,服用任何参数,全自动的值设置name存储属性[Unnamed]通过使用指定的初始化.

class Food {
    let name: String

    // MARK: - designated initializer
    init(name: String) {
        self.name = name
    }

    // MARK: - convenience initializer
    convenience init() {
        self.init(name: "[Unnamed]")
    }
}

// MARK: - Examples
let food = Food(name: "Cheese") // name will be "Cheese"
let food = Food()               // name will be "[Unnamed]"
Run Code Online (Sandbox Code Playgroud)

当您处理大型类时,至少有一些存储属性是很有用的.我建议在Apple Developer门户网站上阅读更多关于选项和继承的内容.


Chr*_*raf 9

便利初始值设定项优于设置默认参数值的地方

对我来说,convenience initializers如果除了简单地为类属性设置默认值之外,还有更多事情要做,则很有用。

具有指定 init() 的类实现

否则,我只会在init定义中设置默认值,例如:

class Animal {

    var race: String // enum might be better but I am using string for simplicity
    var name: String
    var legCount: Int

    init(race: String = "Dog", name: String, legCount: Int = 4) {
        self.race = race
        self.name = name
        self.legCount = legCount // will be 4 by default
    }
}
Run Code Online (Sandbox Code Playgroud)

方便的类扩展 init()

但是,除了简单地设置默认值之外,可能还有更多事情要做,这就是convenience initializers派上用场的地方:

extension Animal {
    convenience init(race: String, name: String) {
        var legs: Int

        if race == "Dog" {
            legs = 4
        } else if race == "Spider" {
            legs = 8
        } else {
            fatalError("Race \(race) needs to be implemented!!")
        }

        // will initialize legCount automatically with correct number of legs if race is implemented
        self.init(race: race, name: name, legCount: legs)
    }
}
Run Code Online (Sandbox Code Playgroud)

使用示例

// default init with all default values used
let myFirstDog = Animal(name: "Bello")

// convenience init for Spider as race
let mySpider = Animal(race: "Spider", name: "Itzy")

// default init with all parameters set by user
let myOctopus = Animal(race: "Octopus", name: "Octocat", legCount: 16)

// convenience init with Fatal error: Race AlienSpecies needs to be implemented!!
let myFault = Animal(race: "AlienSpecies", name: "HelloEarth")
Run Code Online (Sandbox Code Playgroud)

  • 这里解释得很好又简单 (2认同)
  • 仍然是我迄今为止找到的最好的例子! (2认同)

Ser*_*erg 6

可以在类扩展中定义便利初始值设定。但一个标准的- 不能。

  • 虽然根本不是问题的完整答案,但这是我尚未考虑的事情,谢谢! (2认同)

ful*_*oon 6

convenience init使得用值初始化一个类是可选的。

在此处输入图片说明

在此处输入图片说明


jer*_*amo 5

如果您的用例在同一类中的另一个初始化程序中调用初始化程序,这是有道理的。

尝试在操场上这样做

class Player {
    let name: String
    let level: Int

    init(name: String, level: Int) {
        self.name = name
        self.level = level
    }
    
    init(name: String) {
        self.init(name: name, level: 0) //<- Call the initializer above?

        //Sorry you can't do that. How about adding a convenience keyword?
    }
}

Player(name:"LoseALot")

Run Code Online (Sandbox Code Playgroud)

带方便关键字

class Player {
    let name: String
    let level: Int

    init(name: String, level: Int) {
        self.name = name
        self.level = level
    }
    
    //Add the convenience keyword
    convenience init(name: String) {
        self.init(name: name, level: 0) //Yes! I am now allowed to call my fellow initializer!
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您想通过扩展类型为类型创建自己的自定义初始值设定项,这也很有用。

class Player {
    let name: String
    let level: Int

    init(name: String, level: Int) {
        self.name = name
        self.level = level
    }
}

extension Player {
    convenience init(name: String) {
        self.init(name: name, level: 0) 
    }
}
Run Code Online (Sandbox Code Playgroud)