4

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?

Leem
  • 17,220
  • 36
  • 109
  • 159
  • It seems to me you're simply trying to provide private backing variables and `maxProductCount` shouldn't actually be a computed property. In Swift, there's no need for private backing variables and getters and setters. – Dávid Pásztor Oct 04 '18 at 10:02
  • @DávidPásztor OK, but...how to achieve what I would like to achieve? – Leem Oct 04 '18 at 10:04
  • Is there are actual reason you'd want to use private backing variables or is it just because that's how you're used to doing it from Java? Cause if it's the latter, the short answer is: don't look for a workaround, since in most cases in doesn't make sense to achieve what you're trying to achieve in Swift. You should also be aware that if you don't declare the property in the protocol definition itself, only in an extension, it will be an optional protocol requirement, so conforming classes won't have to implement the property. – Dávid Pásztor Oct 04 '18 at 10:07
  • @DávidPásztor, OK, but.. if forget about the code above, my question is trying to solve a real world problem which definitely makes sense. The problem is how to have shared business logic in super abstraction i.e. protocol in Swift (in Java it's abstract class) so that concrete classes which conform to the protocol could benefit from the shared business logic instead of duplicate the logic in each of them in the mean time could implement their own versions of abstract functions declared in protocol. Could you please provide a suggestion on how to achieve this in Swifit? – Leem Oct 04 '18 at 10:15
  • @Leem What you are probably looking for it is a shared instance "Singleton". – Leo Dabus Oct 04 '18 at 10:46
  • You need to implement class like behaviour to an object to reference anything in Swift. – Vanya Oct 06 '18 at 10:22

2 Answers2

4

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
    }
} 
Oni_01
  • 470
  • 5
  • 12
  • Trying to understand: why `return 1` if you already increased the value of `maxProductCount` ? – koen Sep 23 '19 at 13:46
1

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

Ehsan Saddique
  • 638
  • 4
  • 12