Мне трудно понять разницу между обоими или цель convenience init
.
Мне трудно понять разницу между обоими или цель convenience init
.
Ответы:
Стандарт init
:
Назначенные инициализаторы являются основными инициализаторами класса. Назначенный инициализатор полностью инициализирует все свойства, введенные этим классом, и вызывает соответствующий инициализатор суперкласса, чтобы продолжить процесс инициализации вверх по цепочке суперкласса.
convenience init
:
Инициализаторы удобства вторичны, они поддерживают инициализаторы для класса. Вы можете определить вспомогательный инициализатор для вызова назначенного инициализатора из того же класса, что и вспомогательный инициализатор, с некоторыми из параметров назначенного инициализатора, установленными на значения по умолчанию. Вы также можете определить удобный инициализатор для создания экземпляра этого класса для конкретного варианта использования или типа входного значения.
согласно Swift Documentation
Вкратце, это означает, что вы можете использовать удобный инициализатор, чтобы сделать вызов назначенного инициализатора более быстрым и «удобным». Таким образом, для удобных инициализаторов требуется использование 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)
}
Я часто использую их при создании пользовательских представлений и таких, которые имеют длинные инициализаторы с в основном значениями по умолчанию. Документы объясняют лучше, чем я, проверьте их!
Инициализаторы удобства используются, когда у вас есть класс с множеством свойств, из-за которых всегда «утомительно» инициализировать остроумие со всеми этими переменными, поэтому с инициализатором удобства вы просто передаете некоторые переменные для инициализации объект, а остальным присвойте значение по умолчанию. На сайте Рэя Вендерлиха есть очень хорошее видео, не уверен, что оно бесплатное или нет, потому что у меня есть платный аккаунт. Вот пример, где вы можете видеть, что вместо инициализации моего объекта всеми этими переменными я просто даю ему заголовок.
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
Вот простой пример, взятый с портала разработчиков Apple .
В основном назначенный инициализатор - это 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]"
Это полезно, когда вы имеете дело с большими классами, по крайней мере, с несколькими сохраненными свойствами. Я бы порекомендовал узнать больше о дополнительных возможностях и наследовании на портале Apple Developer.
Для меня, convenience initializers
они полезны, если нужно сделать больше, чем просто установить значение по умолчанию для свойства класса.
В противном случае я бы просто установил значение по умолчанию в 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
}
}
Однако здесь может быть что-то большее, чем просто установить значение по умолчанию, и это то, где 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)
}
}
// 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")
Удобный инициализатор можно определить в расширении класса . А вот стандартный - не может.
Это имеет смысл, если ваш вариант использования - вызвать инициализатор в другом инициализаторе в том же классе .
Попробуйте сделать это на детской площадке
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")
С ключевым словом удобства
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!
}
}
Примечание: прочтите весь текст
Назначенные инициализаторы являются основными инициализаторами класса. Назначенный инициализатор полностью инициализирует все свойства, введенные этим классом, и вызывает соответствующий инициализатор суперкласса, чтобы продолжить процесс инициализации до цепочки суперкласса.
Инициализаторы удобства вторичны, они поддерживают инициализаторы для класса. Вы можете определить вспомогательный инициализатор для вызова назначенного инициализатора из того же класса, что и вспомогательный инициализатор, с некоторыми из параметров назначенного инициализатора, установленными по умолчанию.
Назначенные инициализаторы для классов записываются так же, как и простые инициализаторы для типов значений:
init(parameters) {
statements
}
Инициализаторы удобства написаны в том же стиле, но с модификатором удобства, помещенным перед ключевым словом init, разделенным пробелом:
convenience init(parameters) {
statements
}
Практический пример:
class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}
let namedMeat = Food(name: "Bacon")
// namedMeat's name is "Bacon”
Инициализатор init (name: String) из класса Food предоставляется как назначенный инициализатор, потому что он обеспечивает полную инициализацию всех сохраненных свойств нового экземпляра Food. Класс Food не имеет суперкласса, поэтому инициализатору init (name: String) не нужно вызывать super.init () для завершения своей инициализации.
«Класс Food также предоставляет удобный инициализатор init () без аргументов. Инициализатор init () предоставляет имя заполнителя по умолчанию для нового блюда, делегируя его классу Food init (name: String) со значением имени [Безымянный]: »
“let mysteryMeat = Food()
// mysteryMeat's name is "[Unnamed]”
Второй класс в иерархии - это подкласс Food под названием RecipeIngredient. Класс RecipeIngredient моделирует ингредиент в рецепте приготовления. Он вводит свойство Int, называемое количеством (в дополнение к свойству name, которое оно наследует от Food), и определяет два инициализатора для создания экземпляров RecipeIngredient:
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
}
override convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}
Класс RecipeIngredient имеет единственный назначенный инициализатор, init (имя: String, количество: Int), который можно использовать для заполнения всех свойств нового экземпляра RecipeIngredient. Этот инициализатор начинается с присвоения переданного аргумента количества свойству количества, которое является единственным новым свойством, введенным RecipeIngredient. После этого инициализатор передает полномочия инициализатору init (name: String) класса Food.
страница: 536 Отрывок из: Apple Inc. «Язык программирования Swift (Swift 4)». iBooks. https://itunes.apple.com/pk/book/the-swift-programming-language-swift-4-0-3/id881256329?mt=11
Так что это пригодится, когда вам не нужно указывать каждое свойство класса. Так, например, если я хочу создавать все приключения с начальным значением HP, равным 100, я бы использовал следующий удобный init и просто добавил имя. Это сильно сократит код.
class Adventure {
// Instance Properties
var name: String
var hp: Int
let maxHealth: Int = 100
// Optionals
var specialMove: String?
init(name: String, hp: Int) {
self.name = name
self.hp = hp
}
convenience init(name: String){
self.init(name: name, hp: 100)
}
}
Все ответы звучат хорошо, но давайте разберемся с этим на простом примере
class X{
var temp1
init(a: Int){
self.temp1 = a
}
Теперь мы знаем, что класс может наследовать другой класс, поэтому
class Z: X{
var temp2
init(a: Int, b: Int){
self.temp2 = b
super.init(a: a)
}
Теперь, в этом случае при создании экземпляра для класса Z вам нужно будет указать оба значения «a» и «b».
let z = Z(a: 1, b: 2)
Но что, если вы хотите передать только значение b и хотите, чтобы rest принимал значение по умолчанию для других, тогда в этом случае вам нужно инициализировать другие значения значением по умолчанию. Но подождите, как ?, для этого U нужно установить его задолго до этого только в классе.
//This is inside the class Z, so consider it inside class Z's declaration
convenience init(b: Int){
self.init(a: 0, b: b)
}
convenience init(){
self.init(a: 0, b: 0)
}
И теперь вы можете создавать экземпляры класса Z с указанием некоторых, всех или ни одного значения для переменных.
let z1 = Z(b: 2)
let z2 = Z()