快速的代码组织方式:扩展与类和结构

时间:2017-04-10 20:29:00

标签: ios swift

我目前正在开发一款必须解析网址的iOS应用。必须解析的URL始终具有相同的格式。

此类网址的示例:

  

myprotocol://标签姓名=约翰&安培;姓=史密斯

我的第一个想法是编写一个“解析器”,它使用URL的String初始化,并使用 getter 方法返回label,从网址解析firstnamelastname

这类的伪代码:

import Foundation

class URLParser {

    var url: URL

    init(url: String) {
        self.url = URL(string: url)
    }

    func label() -> String? {
        // code to determine label
    }

    func firstname() -> String? {
        // code to determine firstname
    }

    func firstname() -> String? {
        // code to determine lastname
    }
}

但后来我阅读了更多关于Swift扩展的内容,并看到它们在几个places中被使用和推荐。

对于我的用例,我可以为URL类创建一个扩展,它可能如下所示:

import Foundation

extension URL {

    var label: String {
        // code to determine label
    }

    var firstname: String {
        // code to determine label
    }

    var lastname: String {
        // code to determine label
    }
}

一方面使用这样的扩展似乎是一个好主意,因为它感觉非常轻巧和精确。但另一方面它也感觉有点不对,因为值labelfirstnamelastname一般的概念没有任何关系。 URL。它们特定于我的用例。

我希望在我的代码中清楚地传达正在发生的事情,并使用MyUseCaseURLParserURL MyUseCaseURL这类名为{{1}}的类似乎做得更好。

但这完全基于其他语言的过去编程经验。

Swifty 这样做的方式是什么,并围绕它组织代码?除了使用扩展和类之外,还有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

有两件事需要代表:

  1. 解析行为
  2. 解析结果
  3. 您的第一个解决方案很好,但您不应该将其称为URLParser。解析在那里发生,但是类不代表解析器,它代表结果。

    我会将其简化为:

    class MyProtocolData {
        init?(url: URL) {
           // parsing happens here, it's a failable initializer
           // no need to store the URL
        }
    
        let label: String
        let firstName: String
        let lastName: String
    }
    

    您还可以使用struct

    第二种解决方案也没问题。 Apple也使用了这样的解决方案(例如NSDictionary)。但是,这种解决方案的问题是在所有URL个实例上都具有属性,即使是那些不属于您的方案的实例。此外,每次访问函数(或属性)时都必须再次解析URL。

    我使用extension的第一个解决方案是:

    extension URL {
       func parseMyProtocol() -> (label: String, firstName: String, lastName: String)? {
       }
    }
    

    请注意,我们将解析与结果分开。另请注意,该方法的名称不是通用的,它不会与其他解析方法冲突。

    我的第二个解决方案是用结构替换结果元组:

    struct MyProtocolData {
       let label: String
       let firstName: String
       let lastName: String
    }
    
    extension URL {
       func parseMyProtocol() -> MyProtocolData? {}
    }
    

    根据网址所代表的内容,您可能会想到更好的名称,例如: UserDataparseUserData

    正如您所看到的,有多种解决方案,都是惯用的Swift。使用类没有什么不合适的。

答案 1 :(得分:0)

在您的示例中,扩展程序不适合这种情况。如果要提供检查URL是否包含参数的函数,则将使用扩展名。更好的方法是使用带有可用初始化程序的结构,并使用let。

使其不可变
struct CustomURL {
    let url: URL
    let label: String
    let firstname: String
    let lastname: String

    init?(url: URL) {
        //Check if url contains all elements you need, if not return nil
    }
}