Swift Extension: same extension function in two Modules
Asked Answered
S

3

34

Say I have a Framework called SwiftKit, which has a UIView's extension class method named someClassMethod and a property named someProperty within it:

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

And I also have a Framework called SwiftFoundation, which also has a UIView's extension class method named someClassMethod and a property named someProperty within it:

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

Then I created a project introduced these Frameworks, things is, if I import both of them in the same swift file and access those extensions, I got a "Ambiguous use of someProperty/someClassMethod()" error, even if I specified the call in the form of SwiftKit.UIView.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              // error: Ambiguous use of 'somProperty'
        SwiftKit.UIView.someClassMethod()   // error: Ambiguous use of 'someClassMethod()'
    }
}

If I only import one of them, the ambiguous error goes away, but a stranger thing happens:

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()
    }
}

The console prints out:

someProperty from Swift Foundation

someClassMethod from Swift Foundation

My question is: How can I call these extensions(both class/instance method, properties) without ambiguous? If I cannot, does it mean we should add prefix to extension names as we usually do with Objective-C?

Sororate answered 23/9, 2015 at 10:8 Comment(5)
I would assume that ModuleA.UIColor.randomColor() works (assuming that you define it as a class method). Did you try it?Krystalkrystalle
I just checked with a similar extension, and Module.UIColor.myCustomColor() compiled fine.Unheard
@MartinR Thanks for your reply, I have made the question more clear, I'd really appreciate your further help.Sororate
My assumption (I haven't tested it myself): It should work for pure Swift classes, but not for classes inheriting from NSObject, because defining the same method in different class categories is undefined behavior in Objective-C.Krystalkrystalle
Can I suggest clean and build?Ingrowing
T
8

Details

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

Problem

frameworks SwiftFoundation and SwiftKit has the same names of the properties and functions

decision

Way1

Use different names of the properties and functions

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

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

Way2

Group the properties and functions

// 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() }
}

Result

import UIKit
import SwiftKit
import SwiftFoundation

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

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

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

Project

enter image description here enter image description here

Your method

SwiftFoundation.UIView.swiftFoundationSomeClassMethod()

Your variant of using the namespaces is not correct because all UIView extensions from both frameworks are included in you UIView class. Look at image bellow, you can see SwiftKit class and swiftFoundationSomeClassMethod() inside SwiftFoundation. This can confuse other developers.

enter image description here

Threnode answered 1/12, 2016 at 22:18 Comment(0)
B
1

If it's an extension of an ObjC NSObject object e.g. UIView, then yes the extension method requires a prefix.

However, those who find the underscores unsightly can try this alternative that uses Swift protocols to replace the UIColor.red.my_toImage() with UIColor.red.my.toImage() here: Better way to manage swift extensions in your project

Bologna answered 10/6, 2019 at 18:1 Comment(0)
S
1

You can use two different files that import the two different dependencies each. You can then use the public extension from Framework A in File A and the extension from Framework B in File B.

Skiplane answered 4/8, 2022 at 17:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.