В чем разница между удобством init vs init в быстрых, явных примерах лучше

У меня возникают проблемы, чтобы понять разницу между ними и целью удобства 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")