Leem
Leem

Reputation: 18308

How to define variable that can be set and get in extension of protocol

I come from Java world. Now I am programming in Swift 4.

I would like to implement abstract class in Swift, I know in Swift there is no such concept of abstract class. But I know we could mimic this concept in Swift by using protocol. For example this is what I tried:

// With protocol, I can define functions that concrete class have to implement
protocol ProductProvider {
   func getProductNumber() -> Int
}

// with protocol extension, I can define shared (computed) properties and functions among concrete classes that comply with this protocol
extension ProductProvider {
  var maxProductCount: Int {
        return 10
  }
}

But now, I would like to have a shared variable that could be set & get ("shared" means to be shared with classes that comply with this protocol):

extension ProductProvider {
  var maxProductCount: Int {
        set(newValue) {
           // set to what if I couldn't define private stored variable in extension to hold the most recent set value ?
        }
        get{
           // how to return the most recent value set?
        }
  }
}

My question is in the comment of above code. How can I do that set and get for a variable in extension of protocol in Swift 4? If it is impossible, what are the workarounds possible?

Upvotes: 4

Views: 7602

Answers (2)

Oni_01
Oni_01

Reputation: 460

The simplest way i think is define the variable in the protocol with the getter and setter. Then in your conform object you should declare the variable to conformance. An Example:

protocol AbstractObject {

    var maxProductCount: Int { get set }
}

struct ConformObject: AbstractObject {

    var maxProductCount: Int
}

So now you can use your variable in your default implementations

extension AbstractObject {

    mutating func addOne() -> Int {
        self.maxProductCount += 1
        return self.maxProductCount
    }
} 

Upvotes: 4

Ehsan
Ehsan

Reputation: 658

Aside from the discussion if its a right way to achieve what you want, you can use object association.

public final class ObjectAssociation<T: AnyObject> {

    private let policy: objc_AssociationPolicy

    /// - Parameter policy: An association policy that will be used when linking objects.
    public init(policy: objc_AssociationPolicy = .OBJC_ASSOCIATION_RETAIN_NONATOMIC) {

        self.policy = policy
    }

    /// Accesses associated object.
    /// - Parameter index: An object whose associated object is to be accessed.
    public subscript(index: AnyObject) -> T? {

        get { return objc_getAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque()) as! T? }
        set { objc_setAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque(), newValue, policy) }
    }
}

And in your extension

extension SomeType {

    private static let association = ObjectAssociation<NSObject>()

    var simulatedProperty: NSObject? {

        get { return SomeType.association[self] }
        set { SomeType.association[self] = newValue }
    }
}

It is not possible to store Swift types via object association directly. You can store e.g. NSNumber instead of Int.
Source: https://stackoverflow.com/a/43056053/1811810

Upvotes: 1

Related Questions