ios Swift 使用可选的存储属性初始化结构

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37553626/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 09:12:51  来源:igfitidea点击:

Swift Initialize Struct with optional stored properties

iosswift

提问by James

I'm a Swift newbie and I'm trying to get my head around using Structs with optional properties. I've done quite a bit of searching and got something that works but it feels incredibly inefficient so wondered if there's a better/more manageable way of achieving my goal.

我是 Swift 新手,我正在尝试使用带有可选属性的结构体。我已经做了很多搜索并得到了一些有用的东西,但感觉效率非常低,所以想知道是否有更好/更易于管理的方法来实现我的目标。

I'd like to use Structs to represent a business but I have no idea in advance which combination of properties any specific business is likely to have. This seems to mean that I have to create an init() for every possible combination of parameters.

我想使用 Structs 来表示业务,但我事先不知道任何特定业务可能具有哪些属性组合。这似乎意味着我必须为每个可能的参数组合创建一个 init()。

Here's a simplified example (I have many more properties):

这是一个简化的例子(我有更多的属性):

import Foundation

struct Business {
    let name : String
    var web : String?
    var address: String?

    // just the business name
    init(busName: String) {
        self.name = busName
    }

    // business name + website
    init(busName: String, website: String) {
        self.name = busName
        self.web = website
    }

    // business name + address
    init(busName: String, address: String) {
        self.name = busName
        self.address = address
    }

    // business name + website + address
    init(busName: String, website: String, address: String) {
        self.name = busName
        self.web = website
        self.address = address
    }
}

I can then initialise the class like this:

然后我可以像这样初始化这个类:

Business(busName: "Dave's Cafe", website: "http://www.davescafe.com")

Business(busName: "Sarah's Brewhouse", address: "41 Acacia Ave, Smalltown")

Is there no way to create some kind of init() where the parameters are optional? If you could point me in the direction of terms or concepts to search for that would be great.

有没有办法在参数是可选的情况下创建某种 init() ?如果您能指出我要搜索的术语或概念的方向,那就太好了。

回答by dasdom

Use default values:

使用默认值:

init(busName: String, website: String? = nil, address: String? = nil) {
    self.name = busName
    self.web = website
    self.address = address
}

Then you can call the init like this:

然后你可以像这样调用init:

_ = Business(busName: "Foo")
_ = Business(busName: "Foo", website: "www.foo.bar")
_ = Business(busName: "Foo", address: "bar")
_ = Business(busName: "Foo", website: "www.foo.bar", address: "bar")

回答by dasblinkenlight

One approach that you can borrow from other OOP languages is parameter builder pattern. Start with a static method that returns a builder, then add methods for individual parameters, and finally call build():

您可以从其他 OOP 语言中借用的一种方法是参数构建器模式。从返回构建器的静态方法开始,然后为各个参数添加方法,最后调用build()

let bakery = Business
    .withName("Black Forest")
    .andWebSite("www.blackforest.com")
    .andAddress("1 Main St, Springfield, IA 98765")
    .build()

Here is a skeletal implementation that enables this kind of an API:

这是启用这种 API 的骨架实现:

class Business {
    // Users never call this init, it's for the builder to use
    init(name: String, webSite: String?, address: String?) {
        ...
    }
    // Here is the method the users call:
    static func withName(name: String) {
        return BusinessBuilder(name)
    }
    // This class collects parameters before calling init
    class BusinessBuilder {
        var name : String
        var webSite : String?
        var address: String?
        func andAddress(address: String) -> BusinessBuilder {
            self.address = address
            return self
        }
        func andWebSite(webSite: String) -> BusinessBuilder {
            self.webSite = webSite
            return self
        }
        func build() -> Business {
            return Business(name, webSite, address)
        }
        init(name: String) {
            self.name = name
        }
    }
}

This lets you pass as few or as many initializer parameters as you see fit, in any order that you find convenient in a given situation.

这使您可以按照您认为合适的任何顺序传递尽可能少或尽可能多的初始化程序参数,在给定情况下您认为方便的任何顺序。

The main use of this approach is when you do not know which parameters you are going to get, for example, when they come from an XML or a database. You can call andXyzmethods in a loop, and then call build()when you have no other attributes to set.

这种方法的主要用途是当您不知道将获得哪些参数时,例如,当它们来自 XML 或数据库时。您可以andXyz在循环中调用方法,然后build()在没有其他属性要设置时调用。

回答by Jeffrey

hope this could help you

希望这可以帮助你

 struct Business {
    let name : String
    var web : String?
    var address: String?


// you also need use question mark in init progress
init(name: String, web: String?, address: String?) {
    self.name = name
    self.web = web
    self.address = address
    }
}

Once you create a object you could use nil on your optional value For example :

创建对象后,您可以在可选值上使用 nil 例如:

var newBusiness = Business(name: "AWS", web: nil, address: nil)