pshah
pshah

Reputation: 2082

Call generic function from non-generic function in Swift

MMCondition is a protocol defined in Swift, but interoperates with Objective-C (annotated with @objc).

@objc public protocol MMCondition {
    static var name: String { get }
    static var isMutuallyExclusive: Bool { get }
}

I have the following code:

// addCondition cannot be generic as I want it to be accessible from Objective-C as well.
public func addCondition(condition: MMCondition) {
    // How do I initialize OperationConditionImplementer here?
   let operationCondition = OperationConditionImplementer(condition: condition) // doesn't compile
   // Error: Cannot invoke initializer for type 'OperationConditionImplementer<T>' with an argument list of type '(condition: MMCondition)'
   // Can I use condition.dynamicType to init OperationConditionImplementer somehow?
}

struct OperationConditionImplementer<T: MMCondition> {
    let condition: T

    static var name: String {
        return "Silent<\(T.name)>"
    }

    static var isMutuallyExclusive: Bool {
        return T.isMutuallyExclusive
    }

    init(condition: T) {
        self.condition = condition
    }
}

Upvotes: 3

Views: 483

Answers (2)

atxe
atxe

Reputation: 5079

From Objective-C, you can't use generics as stated in the documentation.

You’ll have access to anything within a class or protocol that’s marked with the @objc attribute as long as it’s compatible with Objective-C. This excludes Swift-only features such as those listed here:

  • Generics

...

So you need to remove completely the generics code. One possible solution might be:

@objc protocol MMCondition {
    static var name: String { get }
    static var isMutuallyExclusive: Bool { get }
}

struct OperationConditionImplementer {
    let condition: MMCondition

    var name: String {
        return "Silent<\(condition.dynamicType.name)>"
    }

    var isMutuallyExclusive: Bool {
        return condition.dynamicType.isMutuallyExclusive
    }

    init(condition: MMCondition) {
        self.condition = condition

        // Here decide comparing types
        if condition.dynamicType === ExampleCondition.self {
            print(condition.dynamicType.name)
        }
    }
}

So for instance, if you try it out in a playground:

class ExampleCondition: NSObject, MMCondition {
    static var name: String  = "ExampleCondition"
    static var isMutuallyExclusive: Bool = false
}

let example = OperationConditionImplementer(condition: ExampleCondition())

You'll see "ExampleCondition" printed.

If you eventually switch to pure Swift, you need to specify T when initializing a OperationConditionImplementer.

You can achieve that defining the addCondition method as:

func addCondition<T: MMCondition>(condition: T) {
   let a = OperationConditionImplementer<T>(condition: condition)
}

Upvotes: 2

Joseph Lord
Joseph Lord

Reputation: 6504

Since Swift 2.0 instances of generic classes can implement Objective-C protocols. What won't be possible I believe is having a struct implement the protocol. In fact I expect that your protocol may need to inherit from NSObjectProtocol to be usable in Objective-C which would then prevent you from implementing the protocol with structs or enums.

You also rightly mention that you can't access generic functions from Objective-C.

For a concrete example of using a generic to fulfil an Objective-C protocol have a look at this blog post.

Upvotes: 2

Related Questions