"Ownership keyword removal in protocols": source breaking for ObjC implementations?

“SE-0176-0186: Remove ownership keyword support in protocols” (Pull Request, Proposal, Discussion) made it a warning to specify weak on Swift properties (vars) in protocols.

In other words this now generates a warning:

protocol MyProtocol {  
    // 'weak' should not be applied to a property declaration in a protocol
    // and will be disallowed in future versions  
    weak var delegate: MyDelegate?  

Instead, weak can be omitted from the protocol declaration, and Swift implementions of this protocol can redeclare the property as weak themselves:

class Impl: MyProtocol {  
    weak var delegate: MyDelegate?  

However, this is a problem for ObjC implementations (as of the Xcode 9.3 betas which brought in this warning) since the compiler complains if you redeclare the property and change the strong/weakness:

#import <MyFramework-Swift.h>  
@interface ImplObjC : NSObject <MyProtocol>  
// warning: 'retain (or strong)' attribute on property 'delegate' does
// not match the property inherited from 'MyProtocol'
// [-Wproperty-attribute-mismatch]  
@property (nonatomic, weak, nullable) id<MyDelegate> delegate;  

Alternatively in a private category:

@interface ImplObjC ()        

// error: illegal redeclaration of property in class extension 'ImplObjC'
// (attribute must be 'readwrite', while its primary must be 'readonly')  
@property (nonatomic, weak, nullable) id<MyDelegate> delegate;  

Alternatively synthesizing into a different ivar with __weak:

@interface ImplObjC ()  
    // error: existing instance variable 'm_delegate' for strong property
    // 'delegate' may not be __weak  
    __weak id<MyDelegate> m_delegate;  
@implementation ImplObjC  
@synthesize delegate = m_delegate;  

The only alternative that works is to override the setter and getter for the property and back it with a weak ivar/property. This is ugly and tedious.

We build with “warnings as errors” for ObjC, so this is a source breaking change for our existing code. It doesn’t seem like it would be a good idea to ignore the Wproperty-attribute-mismatch warning. This is a problem for any existing ObjC code that implements Swift protocols like this.

Now, there are legitimate design discussions to be had over whether a delegate property belongs on an abstract protocol, but given how common the (weak) delegate pattern is in ObjC I believe there will be a significant amount of this kind of code in the wild (we ran into this at least).

Is this a known/expected issue and what is the suggested change?

Note: I’ve also posted this to the apple developer forums (https://forums.developer.apple.com/message/298704 - still waiting for moderator approval however). I was a little worried this is too ObjC-specific for the Swift forums but I feel like this fits under the “Using Swift” category.

1 Like

There’s no point in posting this over in the Apple developer forums, because it’s actually a Swift evolution question. SR-0186 is apparently incorrect when it says “as [the keywords] are currently implemented today they don’t have an effect”, since they do have an effect on Obj-C interoperation.

I would agree that ignoring the warning won’t work.

(Your post is in moderation because of the links in the first sentence. The linking policy is stricter over there.)

It’s also worth pointing out the “-Swift.h” generated header now always declares the property as strong, even if you leave the weak in the Swift protocol and ignore the warning.

Uh, hm. @Douglas_Gregor, thoughts?

Does the warning still occur if the @protocol declaration doesn’t declare any ownership on the properties?

Omitting the ownership specifier on the @protocol declaration will default it to strong and yield the same warning sadly.

Can you file a bug for this at https://bugs.swift.org, so we can track it directly as a problem?

I created a bug at https://bugs.swift.org/browse/SR-7182 - I just copied the original post from here. Feel free to trim it down.

1 Like