У меня возникают проблемы, чтобы понять разницу между ними и целью удобства init. спасибо
В чем разница между удобством init vs init в быстрых, явных примерах лучше
Ответ 1
Стандарт 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)
}
Я часто их использую при создании пользовательских представлений, например, с длинными инициализаторами, которые в основном имеют настройки по умолчанию. Документы объясняют лучше, чем я, проверьте их!
Ответ 2
Инициализаторы удобства используются, когда у вас есть класс с множеством свойств, что делает его "болезненным" всегда инициализировать остроумие со всеми этими переменными, поэтому то, что вы делаете с инициализатором удобства, состоит в том, что вы просто передаете некоторые переменные для инициализации объекта и присвоения остальным значения по умолчанию. На веб-сайте Ray Wenderlich есть очень хорошее видео, но не уверен в его бесплатности или нет, потому что у меня есть платный аккаунт. Вот пример, где вы можете видеть, что вместо инициализации моего объекта все эти переменные Im просто дают ему название.
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
Ответ 3
Вот простой пример, взятый из портала 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]"
Это полезно, когда вы имеете дело с большими классами, по крайней мере, с несколькими сохраненными свойствами. Я бы порекомендовал прочитать больше об опциях и наследовании на портале Apple Developer .
Ответ 4
Примечание: прочитайте весь текст
Обозначенные инициализаторы являются первичными инициализаторами для класса. Назначенный инициализатор полностью инициализирует все свойства, введенные этим классом, и вызывает соответствующий инициализатор суперкласса, чтобы продолжить процесс инициализации вплоть до цепи суперкласса.
Инициализаторы удобства являются вторичными, поддерживая инициализаторы для класса. Вы можете определить инициализатор удобства для вызова назначенного инициализатора из того же класса, что и инициализатор удобства, с некоторыми параметрами назначенных инициализаторов, установленными по умолчанию.
Обозначенные инициализаторы для классов записываются так же, как простые инициализаторы для типов значений:
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 name is "Bacon"
Инициализатор init (name: String) из класса Food предоставляется как назначенный инициализатор, потому что он гарантирует, что все сохраненные свойства нового экземпляра Food полностью инициализируются. Класс Food не имеет суперкласса, поэтому инициализатору init (name: String) не нужно вызывать super.init() для завершения его инициализации.
"Класс Food также предоставляет инициализатор удобства, init() без аргументов. Инициализатор init() предоставляет имя заполнителя по умолчанию для нового продукта путем делегирования через init (Имя: String) имя пользователя [Безымянный]:"
"let mysteryMeat = Food()
// mysteryMeat name is "[Unnamed]"
Второй класс в иерархии является подклассом Food под названием RecipeIngredient. Класс RecipeIngredient моделирует ингредиент в рецепте приготовления. Он вводит свойство Int, называемое количеством (в дополнение к свойству имени, которое он наследует от 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 (name: String, количество: Int), который можно использовать для заполнения всех свойств нового экземпляра RecipeIngredient. Этот инициализатор начинается с назначения аргументу прошедшего количества в свойство количества, которое является единственным новым свойством, введенным RecipeIngredient. После этого инициализатор делегирует до инициализатора init (name: String) класса Food.
page: 536 Отрывок из: Apple Inc. "Язык быстрого программирования (Swift 4)". интерактивные книги. https://itunes.apple.com/pk/book/the-swift-programming-language-swift-4-0-3/id881256329?mt=11
Ответ 5
Так что это удобно, когда вам не нужно указывать каждое свойство для класса. Например, если я хочу создать все приключения с начальным значением HP, равным 100, я воспользуюсь следующим условием удобства и просто добавлю имя. Это сильно сократит код.
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)
}
}
Ответ 6
Удобный инициализатор можно определить в расширении класса class extension. Но стандартный - не может.
Ответ 7
Где удобные инициализаторы побеждают установку значений параметров по умолчанию
Для меня 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
}
}
Расширение класса с удобством 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)
}
}
Примеры использования
// 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")