pachun pachun - 1 month ago 27
Swift Question

How to define a Swift protocol with a getter and setter for an Objective-C NSArray

I'm doing this for testing purposes. It helps with dependency injection.

I have an Objective-C library that I've imported into my Swift 3 project. One of the classes in the Objective-C library is defined this way:

@interface Auth : NSObject
@property (strong, readwrite) NSString *clientId;
@property (strong, readwrite) NSArray *scopes;
@end


In my Swift project, I want to define a protocol. The protocol should define 4 methods: 2 setters and 2 getters.

I want the protocol to be defined in a way so that I can reopen the Auth class in Swift with an extension and declare that Auth conforms to my protocol without putting anything in the body of the extension because the Objective-C class already conforms.

Here's my protocol:

protocol AuthProtocol {
var clientID: String! { get set }
}


Here's the extension:

extension Auth: AuthProtocol {}


This works fine. Now I can treat Auth objects as AuthProtocols and have access to setting and getting their clientID property.

The problem arises when I try to make the protocol define the setter and getter for the scopes array. I believe
NSArray
is
Array<AnyObject>
in Swift. Here's what I tried:

protocol AuthProtocol {
var clientID: String! { get set }
var scopes: Array<AnyObject> { get set }
}


Now the line which reopens
Auth
for extension complains that


Type
Auth
does not conform to protocol
AuthProtocol



Xcode suggests a solution when I click on the error, which adds this code to the body of the exention:

extension Auth: AuthProtocol {
internal var scopes: Array<AnyObject> {
get {
<#code#>
}
set {
<#code#>
}
}
}


This code now has an error on the
internal
line:


scopes
used within its own type


How do I define
AuthProtocol
with a getter and setter for the
scopes
array so that this line:

extension Auth: AuthProtocol {}


Doesn't complain?

All this indicates to me that the problem has to do with the
NSArray
type.

Answer

you can use Xcode to show you exactly what the protocol should be by using the "Generated Interface" command:

Generated Interface Prompt

this jumps you to the generated code:

open class Auth : NSObject {
    open var clientId: String!
    open var scopes: [Any]!
}

transform this generated class definition into the correct protocol definition:

protocol AuthProtocol {
    var clientId: String! { get set }
    var scopes: [Any]! { get set }
}

// doesn't complain anymore
extension Auth: AuthProtocol {}