How to Make a Weak Protocol Reference in 'Pure' Swift (Without @Objc)

How can I make a weak protocol reference in 'pure' Swift (without @objc)

You need to declare the type of the protocol as AnyObject.

protocol ProtocolNameDelegate: AnyObject {
// Protocol stuff goes here
}

class SomeClass {
weak var delegate: ProtocolNameDelegate?
}

Using AnyObject you say that only classes can conform to this protocol, whereas structs or enums can't.

Confusions about weak delegate in swift

should make the delegate to be "weak"

The answer is that if MyProtocol is not restricted to classes, you cannot make it weak, the compiler won't let you.

The reason for the above is that structs are value types. There isn't a reference that can be strong or weak, because logically the entire struct is copied in when you assign the delegate.

how can I avoid retain cycle?

This means that you have got to be careful that your delegate contains no strong references back to the instance of the class. So, for instance

struct ConcreteDelegate: MyProtocol
{
fun someFunc() {}
var instance: AClass

init()
{
instance = AClass()
instance.delegate = self
}
}

Causes a reference cycle. It can be broken by declaring instance as

    weak var instance: AClass! 

Alternatively, and a better solution (IMO), your protocol functions can pass the instance as a parameter so the delegate never needs to store a reference to the instance.

protocol MyProtocol {
func someFunc(caller: AClass)
}

You'll see the above approach adopted in Cocoa in lots of places, for example with the table view data source protocol.

Swift expose the protocol to objc in protocol oriented programming

Add the @objc attribute on the protocol method to specify a different method name to be exposed to Objective-C, in this case match it to the relevant method of AVCaptureDevice (authorizationStatusForMediaType:):

@objc // added this attribute
public protocol PermissionProvider {
@objc(authorizationStatusForMediaType:) static func authorizationStatus(for mediaType: AVMediaType) -> AVAuthorizationStatus
}
extension AVCaptureDevice: PermissionProvider {}

Why?

When Objective-C methods are mapped into Swift, argument descriptions that match the type of the corresponding parameter are pruned (see SE-0005 'Better Translation of Objective-C APIs into Swift'), but when Swift is mapped into Objective-C a corresponding 'de-pruning' doesn't happen.

For example, if in Objective-C we have defined:

- (NappingStatus)nappingStatusForKoala:(Koala *)koala;

- (NappingStatus)nappingStatusForEchidna:(Koala *)koala;

when mapped into Swift these will become:

func nappingStatus(for: Koala) -> NappingStatus

func nappingStatus(forEchidna: Koala) -> NappingStatus

Notice in the first method Koala has been pruned from the parameter name because it matches the type of the parameter it is describing, but in the second method Echidna hasn't been pruned because this doesn't match the type of of the parameter it is describing (Koala).

When mapping from Swift to Objective-C, reversal of this pruning doesn't happen. For example, if in Swift we have defined

func nappingStatus(for: Koala) -> NappingStatus

when mapped into Objective-C it will become:

- (NappingStatus)nappingStatusFor:(Koala *)koala;

So for your case the AVCaptureDevice method in Objective-C that is:

+ (AVAuthorizationStatus)authorizationStatusForMediaType:(AVMediaType)mediaType;

in Swift is mapped to (notice MediaType pruned):

class func authorizationStatus(for mediaType: AVMediaType) -> AVAuthorizationStatus

However your protocol method, which in Swift is:

static func authorizationStatus(for mediaType: AVMediaType) -> AVAuthorizationStatus

when mapped into Objective-C will be (notice MediaType not `de-pruned'):

+ (AVAuthorizationStatus)authorizationStatusFor:(AVMediaType)mediaType;

which doesn't match the Objective-C method in AVCaptureDevice, so we just provide the correct Objective-C method name via the @objc attribute:

@objc(authorizationStatusForMediaType:) static func authorizationStatus(for mediaType: AVMediaType) -> AVAuthorizationStatus

iOS - Pass Data from Swift to ObjC VC using protocol and delegate

Very basic example...

Assuming we have in Storyboard:

  • an Objective-C controller ObjcViewController with a "Present It" button
  • a Swift controller SwiftViewController with a "Done" button, with Identifier: "SwiftVC"

and the buttons are connected to the IBAction methods...

ObjcViewController.h

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface ObjcViewController : UIViewController

@end

NS_ASSUME_NONNULL_END

ObjcViewController.m

#import "ObjcViewController.h"

#import "YourProject-Swift.h"

@interface ObjcViewController () <DataEnteredDelegate>

@end

@implementation ObjcViewController

- (IBAction)goToSwiftVC:(id)sender {

SwiftViewController *vc = (SwiftViewController *)[self.storyboard instantiateViewControllerWithIdentifier:@"SwiftVC"];
[vc setMyDelegate:self];
[self presentViewController:vc animated:YES completion:nil];

}

- (void)userDidEnterInformationWithInfo:(NSString * _Nonnull)info {
NSLog(@"Delegate sent back: %@", info);
}

@end

SwiftViewController.swift

import UIKit

@objc public protocol DataEnteredDelegate {
func userDidEnterInformation(info: String)
}

class SwiftViewController: UIViewController {

@objc public var myDelegate: DataEnteredDelegate?

@IBAction func doneBtn(_ sender: Any) {
myDelegate?.userDidEnterInformation(info: "from SwiftVC")
self.dismiss(animated: true, completion: nil)
}

}

why do I have to mark both the protocol & contained optional functions in a swift protocol as @objc?

UICollectionViewDataSource is imported from ObjC. The auto-generated Swift header doesn't insert @objc on every element. It is common for these headers to be invalid Swift (for example, they define structs and classes without implementations, which isn't valid Swift).

When you're writing Swift (rather than looking at auto-generated headers), you need to tell the compiler that it needs to bridge certain things to ObjC, and you do that with @objc. Imported ObjC doesn't have to be bridged.



Related Topics



Leave a reply



Submit