Is it possible to hash a Swift protocol? - ios

I am trying to write a registry in Swift that maps from API's (Protocols) to Implementations (Classes). I would like to be able to provide the registry an API and receive back an instance of the class that implements it. In Objective-C this was fairly trivial - just call NSStringFromProtocol on the protocol and then use that as a key for a dictionary containing the classes that implement them. In Swift, however, we do not have this introspective capability. When I try to do the same I am told that MyAPI.protocol does not have a member "mirrorType". My question to you is how, in Swift, without using #objc protocols, I can map from a protocol itself to the class that implements it. Thanks!

By now it's not possible without using #objc. The solution I've found in this case is using the protocol name (string) as a key for the dictionary for this implementations (In my case I'll always have only one instance per Protocol).
Using #objc will force you to have all your implementations returning AnyObject the equivalent (id) in objective-C (if your function does not return a native objective-C type).
Hope that helps.

Related

How to use Struct as Observer in NotificationCenter

In NotificationCenter Class , Why apple has created Observer of type Any?
func addObserver(Any, selector: Selector, name: NSNotification.Name?, object: Any?)
My Reasoning.
If observer is struct then on assigning inside as function parameter, It will be copied then how my observer can receive the notification.
I can't write any function which uses #objc prefix in Struct.
Selector is always be type of #objc.
So What is the use of Any in addObserver.....
It should always be of type AnyObject.
Secondly we already known that NotificationCenter keep the weak copy of observer, And we can't use weak modifier for type Any. Then how apple is managing all this?
Any help in understanding this concept is highly appreciated.
No one chose to make this parameter Any. It's just what they got by default. It's automatically bridged from ObjC:
- (void)addObserver:(id)observer
selector:(SEL)aSelector
name:(nullable NSNotificationName)aName
object:(nullable id)anObject;
The default way that id is bridged is Any. It hasn't been specially refined for Swift. In practice, you can't really use structs meaningfully here. The fact that the compiler won't stop you from calling it in an unhelpful way doesn't imply that it's intended to be used that way.
Why type Any? - because in Objective C it is type id.
Why you can't mark your function as #obj - #obc is the keyword for Swift code which indicates what compiler should add this method to a header file for this Class, yes you can make headers only for Classes.
Selector also is the objective-c term, it just says which function to invoke, similar to msg_send
In NotificationCenter Class , Why apple has created Observer of type Any.
Because all Objective-C id declarations are translated into Swift as Any.
You might object that this really should be AnyObject, because only a class will work here. And indeed, that's the way id used to be translated into Swift. But nowadays you can pass anything where an id is expected, because if it's something Objective-C can't understand, it will be boxed up as a class instance (e.g. as a _SwiftValue) so that it can make the round-trip into Objective-C and back again to Swift. Therefore id is translated as Any.
However, just because you can pass a struct here doesn't mean you should. It won't work, as you've discovered. Objective-C cannot introspect a Swift struct.
There are lots of situations like this, where Cocoa gives you enough room to hang yourself by passing the wrong thing. The contents of a CALayer is typed as Any, but if you pass anything other than a CGImage, nothing will happen. The layerClass if a UIView is typed as AnyClass, but you'd better pass a CALayer subclass. I could go on and on.

How to access a List property of a swift class from an Objective C class

I have this swift model class (using Realm) that has a simple String property and a List of strings. I can easily access the string property from an Objective-C class, but it doesn't seem to work when I try to access the List property.
Code:
class MyClass: Object, Mappable {
dynamic var stringProperty: String?
let listOfStrings = List<StringValue>()
}
I tried creating a getter method that returns a simple array from the List property, but I wonder if there is a better way.
One of the first things that the Realm Swift documentation says is:
If you’re looking to use Realm from Objective‑C, or from mixed Objective‑C & Swift apps, please see Realm Objective‑C instead. The Realm Objective‑C and Realm Swift APIs are not interoperable and using them together is not supported.
There is some limited, unofficial support for interoperability with Objective-C available that may help you, but it's really intended for only very narrow use cases (primarily to allow writing frameworks that wish to support models written in both Realm Objective-C and Realm Swift). The general advice is that if you want to access your Realm models from both Objective-C and Swift, use Realm Objective-C.

Usage of Extensions for implementing delegate functions in Swift

I know that Objective-C categories are called extension in Swift.
But recently i bumped in to this :
extension MyClass : GMSMapViewDelegate
{
func mapView(mapView: GMSMapView, idleAtCameraPosition position: GMSCameraPosition)
{
print("idleAtCameraPosition")
self.getAddressFromLocation(mapView.camera.target)
}
}
This looked like they are implementing delegate functions.This seemed a very good and clean way of implementing delegate functions. So I personally tried it and this works but I think I may be wrong because categories i.e. extensions are not supposed to do this.They were used to add extra functionality to other classes with out subclassing.
So my question is can we use extensions for such purpose or not?
If we can do this then extensions are more than just categories.Because i don't think we could achieve this by categories in Objective-C.
Thanks
From the official Swift Language Reference:
Extensions in Swift can:
Add computed instance properties and computed type properties
Define instance methods and type methods
Provide new initializers
Define subscripts
Define and use new nested types
Make an existing type conform to a protocol
Yes, extensions are a valid method to make a class conform to a delegate protocol.
Not only are extensions valid for this purpose, but they allow for better code organization and follow good style practice in Swift.
Yes you can, and should, do that. Putting the methods that implement a protocol into a class extension is considered good style in Swift. It separates out groups of methods based on what they do. I would suggest making liberal use of extensions in your coding.
Yes, extensions are meant to be able to allow existing classes to conform to new protocols, in addition to just adding functions to a class.

Implement a Swift protocol by automatically mapping method calls to keys in a dictionary

In Objective C I have previously been able to implement an automatic mechanism to allow an object with a private NSDictionary property to implement a simple protocol by automatically converting method invocations to dictionary 'valueForKey' requests, and passing these to the dictionary that has the appropriate key:value.
For example, I would have an object 'ABCArtist', which would implement the artistProtocol. This protocol has a method -(NSString*)artistName; and the 'ABCArtist' object would implement this method by returning [self.privateDictionary valueForKey:artistName];
This process relied on overriding the NSObject methods:
- (void)forwardInvocation:(NSInvocation *)invocation;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector;
- (id)forwardingTargetForSelector:(SEL)aSelector;
I have tried to apply the same process in Swift, however I am unable to use this as I get the compiler error:
'NSInvocation' is unavailable in Swift: NSInvocation and related APIs
not available
Is there any way that anyone has found to implement a protocol by automatically querying a dictionary for a value with the same name as the protocol method?
The use case for this is in mapping to a dictionary of JSON content returned from an API, if this automatic mapping can be accomplished, I only need to write the protocol, and forward it to the generated JSON dictionary.
That kind of dynamic handling of arbitrary messages at runtime can only be done in Objective-C. For one thing, calls to pure Swift methods don't even go through the Objective-C dynamic dispatch mechanism. So it would have to be an #objc method, and the forwardInvocation: logic will have to be implemented in Objective-C.

Swift version of NSObject+AutoCoding

I use this auto coding lib a lot through my projects.
https://github.com/nicklockwood/AutoCoding
I think it is very useful. So I am wondering how I can implement the same extension in Swift?
Thanks.
Additional question:
Is it possible to write AnyObject into a file? Or it has to inherit from NSObject and conform NSCoding protocol?
From looking at this project, the object does not have to conform to NSCoding. But only Objective-C properties are saved. So for a Swift object, it will only work with the properties that are visible to Objective-C (with #objc and/or dynamic, and the type of the property is one that can be bridged to an Objective-C type).
I wrote a little utility that simplifies NSCoding in Swift: https://github.com/mustafa/SwiftCoding

Resources