Swift equivalent of id<MyProtocol>? - objective-c

The question is in the title. In Objective-C, if I want to have a property (like a delegate) that HAS to adhere to a certain protocol it can be defined like so:
#property (weak) id<MyDelegate> delegate;
How can I do this in Swift?

A protocol is a type, so you can use it as a declared variable type. To use weak, you must wrap the type as an Optional. So you would say:
weak var delegate : MyDelegate?
But in order for this to work, MyDelegate must be an #objc or class protocol, in order to guarantee that the adopter is a class (not a struct or enum, as they cannot be weak).

I think the exact oposite is:
weak var delegate: protocol<MyDelegate>?
I prefer this old, objc, style over the swift syntax because in swift first is the base class and then all the adopted protocols. This may be confusing in case your protocol does not have "Delegate" suffix as you won't know whether DataAdoption(for example) is super class or a protocol.

Use the protocol like a type, so:
weak var delegate:MyDelegate?

It is also good to know the equivalent for the Objective-C id<MyProtocolName> in the method declaration in Swift is protocol<MyProtocolName>. For Example:
// Objective-C
-void myMethodWithSome:(id <MyProtocolName>)param {
// ...
}
// Swift
func myMethodWithSome(param: protocol<MyProtocolName>) {
//...
}

Update for method declarations
Objective-C
-void myMethodWithSome:(id <MyProtocolName>)param {
// ...
}
Swift
func myMethodWithSome(param: MyProtocolName) {
//...
}

Related

Implement an Objective-C method with light weight generics in Swift

I have to implement this method in a DataSource protocol of an Objective-C library
(nullable id<SomeClass>)someMethod;
I am trying to implement it in my class in Swift, specifically, the AppDelegate, with what I believe keeps equal the signature
extension AppDelegate: LIBDataSource {
#objc func someMethod<T: SomeClass>() -> T? {
return nil // temporary
}
}
The problem is that
As it is, I have a warning and an error. The error says Method cannot be marked #objc because it has generic parameters (the warning below is also shown)
If I remove #objc, the warning says Non-#objc method 'someMethod()' cannot satisfy optional requirement of #objc protocol LIBDataSource
Is there a way to implement a generic Obj-C method of a Obj-C protocol in Swift? Or do I have to do a separate Objective-C class to accomplish this?
The syntax
id<SomeClass>
is nothing to do with lightweight generics, it means "any Objective-C class as long as it conforms the protocol SomeClass". Your method doesn't need to be generic but it does need to return an object that conforms to the SomeClass protocol. It's signature should probably be something like
func someMethod() -> SomeClass?

How to use NSSet<Class> in Swift (exported as Set<NSObject>)?

I have to fulfill a protocol requirement that is defined in Objective-C like this:
#protocol AProtocol <NSObject>
+ (NSSet<Class> * _Nullable)someClasses;
#end
I want to implement this protocol in a subclass written in Swift. I want to return a Set of classes of another Object. The class I want to return is defined like this:
class B: NSObject {}
The class that conforms to the protocol is defined like this:
class A: NSObject, AProtocol {
static func someClasses() -> Set<NSObject>? {
return [B.self]
}
}
Why is NSSet<Class> bridged to Set<NSObject> instead of Set?
This solution is crashing, how can I solve the problem?
NSSet<Class> is bridged to Set<NSObject> because AnyClass does not conform to Hashable which is a precondition for the ValueType of Set.
It can be solved with the following extension for NSObjectProtocol:
extension NSObjectProtocol where Self: NSObject {
static var objcClass: NSObject {
return (self as AnyObject) as! NSObject
}
}
This returns the class of the object casted as NSObject. It is necessary to cast it first to AnyObject because the type system of Swift is so strong that it would not compile or give a warning when directly casting a type to an instance type. In Objective-C this is fine because Class is also just an object. Since NSObject is implemented in Objective-C and the extension is just for NSObjectProtocol, this is save to use (even with the force cast).
Implementing the extension on NSObjectProtocol and not on NSObject itself brings the positive effect that it is not exported to Objective-C.

Crash when calling Obj-C property from Swift extension

Using this Objective-C property:
#interface TSOnboardingPersonalizeViewController
#property (nonatomic, weak) NSObject<PersonalizeContentCoordinatorDelegate> * _Nullable delegate;
#end
crashes in a Swift extension like this:
extension TSOnboardingPersonalizeViewController {
func next() {
self.delegate?.performAction(.Forward)
}
}
POing self.delegate shows:
(lldb) po self.delegate
▿ Optional<protocol<PersonalizeContentCoordinatorDelegate>>
▿ Some : <MyApp.PersonalizeContentCoordinator: 0x8e964cf58140>
But it doesn't crash if I cast the property to the protocol type:
extension TSOnboardingPersonalizeViewController {
func next() {
if let delegate = self.delegate as? PersonalizeContentCoordinatorDelegate {
delegate.performAction(.Forward)
}
}
}
POing delegate shows:
(lldb) po delegate
<MyApp.PersonalizeContentCoordinator: 0x7f86bcf59930>
Why do I need to explicity cast the property to the PersonalizeContentCoordinatorDelegate protocol type?
I'm using Swift 2.2 and Xcode 7.3
I think it could be due to the fact that the delegate is an NSObject, which probably doesn't have a performAction method. So, even though the delegate conforms to the protocol in Objective-C, Swift probably sees an NSObject (which doesn't include that method).
This seems like a "Lost in Translation" sort of thing, where Objective-C is telling Swift "This object conforms to this protocol." Then when executed, Swift tries calling that method on an NSObject which obviously doesn't include that method and crashes. This would explain why casting would work, because until you tell Swift you have an object of a certain type, it can't execute any of that type's specific methods (even if the underlying object actually is that type).
This is just a guess, though and should definitely be taken with a grain of salt (and maybe a better answer if one comes along).

Concrete class type conforming to protocol in Swift

I need to declare a variable with type UIViewController that conforms to a custom protocol I made. Normally, I would do this in ObjC:
UIViewController<MyProtocol> *thingie;
But, I have no idea how to accomplish that in swift.
I'm just casting the object for now, till something useful shows up:
let conformingObject = viewController as MyProtocol
You may achieve something similar by using generics. Something like this:
class SomeClass<T where T: UIViewController, T: MyProtocol> {
var thingie: T
}

Define method with closure in an #objc protocol

I have the following protocol definition:
#objc protocol PersonDataStore {
func findPersonWithId(remoteId: String, completionBlock: ((Person) -> Void)!)
// ...
}
The error I get is that the second parameter cannot be represented in Objective-C. I researched the blocks/closures topic but I have a hard time getting my head around it since it is so conceptually different.
Is this just a matter of syntax or is it really not possible to define an Objective-C protocol with a closure in Swift?
I believe your problem is that your class Person is not a subclass of NSObject. Add #objc to the declaration of your Person class or make it a subclass of NSObject and your protocol definition should work.