提问者:小点点

Swift扩展:两个模块中的相同扩展功能


假设我有一个名为SwiftKit的框架,它有一个名为的UIView扩展类方法和一个名为的属性:

// SwiftKit
public extension UIView {
    class func someClassMethod() {
        print("someClassMethod from Swift Kit")
    }
    
    var someProperty: Double {
        print("someProperty from Swift Kit")
        return 0
    }
}

我还有一个名为SwiftFoundation的Framework,它还有一个UIView的扩展类方法,命名为一个类方法,其中有一个属性命名为一个属性:

// SwiftFoundation
public extension UIView {
    class func someClassMethod() {
        print("someClassMethod from Swift Foundation")
    }
    
    var someProperty: Double {
        print("someProperty from Swift Foundation")
        return 0
    }
}

然后我创建了一个引入这些框架的项目,事情是,如果我在同一个swift文件中导入它们并访问这些扩展名,我得到了一个“模棱两可地使用一些属性/一些类方法()”的错误,即使我以SwiftKit. UIView.一些类方法()的形式指定了调用:

import UIKit
import SwiftKit
import SwiftFoundation

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        self.view.someProperty              // error: Ambiguous use of 'somProperty'
        SwiftKit.UIView.someClassMethod()   // error: Ambiguous use of 'someClassMethod()'
    }
}

如果我只导入其中一个,模棱两可的错误就会消失,但会发生更奇怪的事情:

import UIKit
import SwiftKit
//import SwiftFoundation

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        self.view.someProperty
        SwiftKit.UIView.someClassMethod()
    }
}

控制台打印出:

来自斯威夫特基金会的一些财产

来自Swift Foundation的一些类方法

我的问题是:如何在没有歧义的情况下调用这些扩展(类/实例方法、属性)?如果我不能,这是否意味着我们应该像通常使用Objective-C那样为扩展名称添加前缀?


共3个答案

匿名用户

  • Swift 3,Xcode 8.1
  • Swift 4,Xcode 9.1
  • Swift 5.1,Xcode 11.2.1

框架SwiftFoundation和SwiftKit具有相同的属性和函数名称

使用不同的属性和函数名称

// SwiftFoundation
public extension UIView {
    public class func swiftFoundationSomeClassMethod() {
        print("someClassMethod from Swift Foundation")
    }

    public var swiftFoundationSomeProperty: Double {
        print("someProperty from Swift Foundation")
        return 0
    }
}

对属性和函数进行分组

// SwiftKit
public extension UIView {
    public class SwiftKit {
        public class func someClassMethod() {
            print("someClassMethod from Swift Kit")
        }

        public var someProperty: Double {
            print("someProperty from Swift Kit")
            return 0
        }
    }

    var SwiftKit: SwiftKit { return SwiftKit() }
}
import UIKit
import SwiftKit
import SwiftFoundation

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        _ = view.SwiftKit.someProperty
        UIView.SwiftKit.someClassMethod()

        _ = view.swiftFoundationSomeProperty
        UIView.swiftFoundationSomeClassMethod()
    }
}

SwiftFoundation.UIView.swiftFoundationSomeClassMethod()

您使用命名空间的变体是不正确的,因为来自这两个框架的所有UIView扩展都包含在您的UIView类中。请看下面的图片,您可以在SwiftFoundation中看到SwiftKit类和swiftFoundation一些类方法()。这可能会让其他开发人员感到困惑。

匿名用户

如果它是ObjCNSObject对象的扩展,例如UIView,那么是的扩展方法需要前缀。

然而,那些觉得下划线难看的人可以尝试使用Swift协议来替换UIColor.red的替代方案。my_toImage()UIColor.red.my. toImage()在这里:更好的方法来管理项目中的swift扩展

匿名用户

您可以使用两个不同的文件,每个文件导入两个不同的依赖项。然后,您可以在文件A中使用来自框架A的公共扩展名,在文件B中使用来自框架B的扩展名。