iOS进阶指南Swift 专栏Swift学习

Swift 命名空间形式扩展的理解和问题探讨

2019-02-12  本文已影响9人  黑羽肃霜

先从 Swift 协议扩展的语法说起

注:协议扩展 Protocol extension: Swift 1.x 中,extension 仅 只能作⽤在实际的类型上 (也就是 class , struct 等等),⽽不能扩展⼀个 protocol.

我们先来看一个例子,从例子中声明协议扩展的语法,然后引出为什么要使用协议扩展,它和 OC 之间的对比在哪里

协议扩展语法的代码

protocol P {
    func method1() -> String
}

extension P {
    func method1() -> String {
        return "hi"
    }
    func method2() -> String {
        return "hi"
    }
}

struct S: P {
    func method1() -> String {
        return "hello"
    }
    func method2() -> String {
        return "hello"
    }
}

let s = S()
let p = s as P
print(p.method1()) // hello
print(p.method2()) // hi

print("---")
print(s.method1()) // hello
print(s.method2()) // hello

说明

上面这段代码,节选自喵神的 《Swifter tips》. 我稍微将协议的名称和结构体的名称作了修改,便于自己阅读。

分析


协议扩展解决了什么问题

关于第一点,

《Swifter-tips》 中 可选协议和协议扩展 一小节给出了扩展协议的一个用途。
简单来说就是,从语法上来看,OC 有提供可选协议,但是 Swift 协议中的函数一旦被声明,就要实现它。但是我们可以通过协议扩展,将可选的方法,放在扩展中。

// 摘自 《Swifter-tips》
protocol OptionalProtocol {
        func optionalMethod()
        func necessaryMethod()
    }
    
    extension OptionalProtocol {
        func optionalMethod() {
            print("Implemented in extension") // 也可以什么都不写
        }
    }
    
    class MyClass: OptionalProtocol {
        func necessaryMethod() {
            print("Implemented in Class3")
        }
        
        func optionalMethod() {
            print("Implemented in Class3")
        }
    }

关于第二点:

我本来想尝试解释,但是想来想去,总觉的不得要领。详细的还是看下这篇文章(Swift 命名空间形式扩展的实现)的描述,我觉得讲的还是很到位的。

这里摘抄下面这段话来可以作为解答 为什么要用命名空间形式扩展来实现 category 的效果

Objective-C 时代的通行解决办法是在扩展方法名字的最前面加上 XXX_ 形式的前缀。这种形式不但解决了命名冲突的问题,而且增强了代码可读性。一旦阅读到这种风格的方法名,就知道是非系统的实现。Swift 社区最初的一段时间内,也是按照这种命名方式来做的

实际的开发过程中,也经常会对系统库中的已有类型做自定义的扩展,如果有一种通用的形式,来实现这种扩展,那就太好了

注: 这里说的意思,距离说明,假设我有一个扩展字符串的方法,以前的办法是

看完之后,还是觉得有点深奥。以下是我个人的理解:

OC 时代,没有命名空间的概念,所以使用了前缀来实现 category的区分。swift 时代从语法上增加了命名空间,扩展的实现,不需要增加前缀。但是因为这样的便利,带来了一些别的问题:

举例说明:

如果工程中引用了不同的第三方库,而包括主工程在内,都对 String 做了扩展,扩展的函数名都叫 isTestExtensionMethod, 可能造成调用时产生重叠,无法执行到目标代码。
因此,从形如 aString.isTestExtensionMethod() 的调用,改为避免冲突的 形如 aString.myCategory.isTestExtensionMethod.

所以其实讲到这里,才引出这篇文章的标题 —— 命名空间形式扩展 是如何实现的(略啰嗦)

命名空间形式扩展

https://zhang759740844.github.io/2017/11/14/RxSwift%E5%8E%9F%E7%90%86/

上一篇 下一篇

猜你喜欢

热点阅读