Необязательный параметр инициализатора класса в инициализаторе класса в Swift - PullRequest
0 голосов
/ 11 июля 2019

У меня есть класс init с именем User, а класс User содержит некоторые параметры.Теперь в классе Offer вы видите, что я передаю класс User в качестве параметра, но вместо этого я хочу, чтобы он был необязательным.Есть ли способ иметь дополнительный класс в ваших параметрах?Спасибо

struct User {
    let uid: String
    let username: String

    init(uid: String, dictionary: [String: Any]) {
        self.uid = uid
        self.username = dictionary["username"] as? String ?? ""
    }
}

struct Offer {
    let user: User
    let caption: String
    let imageURL: String
    let creationDate: Date

    init(user: User, dictionary: [String: Any]) {
        self.user = user
        self.caption = dictionary["caption"] as? String ?? ""
        self.imageURL = dictionary["image_url"] as? String ?? ""

        let secondsFrom1970 = dictionary["creation_date"] as? Double ?? 0
        self.creationDate = Date(timeIntervalSince1970: secondsFrom1970)
    }
}

Ответы [ 2 ]

1 голос
/ 11 июля 2019

Ваш код запутывает две разные вещи: инициализацию объекта с набором значений для его элементов и извлечение этих элементов из словаря.Просто напишите два отдельных инициализатора:

import Foundation

struct User {
    let uid: String
    let username: String

    /*
    // Due to the absence of an explicit initializer declaration,
    // the compiler will synthesize an implicit member-wise initailizer like this:
    init(uid: String, username: String) {
        self.uid = uid
        self.username = username
    }
    */
}

extension User {
    // Putting this initializer in an extension preserves he member-wise intializer
    init?(fromDict dict: [String: Any]) {
        guard let uid = dict["uid"] as? String,
              let username = dict["username"]  as? String
        else { return nil }

        self.init(uid: uid, username: username)
    }
}

struct Offer {
    let user: User
    let caption: String
    let imageURL: String
    let creationDate: Date

    /*
    // Due to the absence of an explicit initializer declaration,
    // the compiler will synthesize an implicit member-wise initailizer like this:
    init(
        user: User,
        caption: String,
        imageURL: String,
        creationDate: Date
    ) {
        self.user = user
        self.caption = caption
        self.imageURL = imageURL
        self.creationDate = creationDate
    }
    */
}

extension Offer {
    // Putting this initializer in an extension preserves he member-wise intializer
    init?(fromDict dict: [String: Any]) {
        guard let user = dict["user"] as? User,
              let caption = dict["caption"] as? String,
              let imageURL = dict["image_url"] as? String,
              let secondsFrom1970 = dict["creation_date"] as? Double
        else { return nil }

        self.init(
            user: user,
            caption: caption,
            imageURL: imageURL,
            creationDate: Date(timeIntervalSince1970: secondsFrom1970)
        )
    }
}

Некоторые примечания:

  1. Использование оператора nil-coalescing (??) для предоставления бессмысленных значений по умолчанию в случае nil действительно плохая практика.Он скрывает сбои и незаметно вводит проблемы целостности данных;не делайте этого.
  2. String не подходит для члена с именем imageURL.Используйте URL.
  3. Если эти указания поступают из JSON, используйте протокол Codable для автоматизации всего этого стандартного кода.
  4. String плохой тип для ID в первую очередь потому, что он очень медленный по сравнению с более подходящими типами, такими как UUID и Int.Это особенно верно в большинстве баз данных, где текстовое сравнение на намного медленнее, чем сравнение Int / UUID.
0 голосов
/ 11 июля 2019

Прежде всего, это не class, это struct, и они оба разные.

Вы можете легко создать необязательный аргумент, как показано ниже.Вам также необходимо пометить свойство user как необязательное.

struct Offer {
    let user: User?
    let caption: String
    let imageURL: String
    let creationDate: Date

    init(user: User? = nil, dictionary: [String: Any]) {
        self.user = user
        self.caption = dictionary["caption"] as? String ?? ""
        self.imageURL = dictionary["image_url"] as? String ?? ""

        let secondsFrom1970 = dictionary["creation_date"] as? Double ?? 0
        self.creationDate = Date(timeIntervalSince1970: secondsFrom1970)
    }
}
...