Passing dictionary objects to Objective C protocol in Swift - ios

I'm trying to pass a dictionary object to an Objective C protocol using swift.
the protocol code snippet is as follows:
#protocol MessageDelegate
- (void)handleNewMessageArrived:(NSDictionary *)messageContent;
#end
and this is the swift class the implements the protocol:
class ViewController: UIViewController, MessageDelegate
{
...
func handleNewMessageArrived(messageContent : NSDictionary!)
{
...
}
}
But the build fails, and the error I get is:
"the type 'ViewController' does not conform to protocol 'MessageDelegate"
I looked at this SO Question but it deals with a specific object type.
is there an error in the way I declare\implement the delegate method? or in the way I assume the arguments are mapped in swift?
I'm new to Swift so any Help will be much appreciated.

Try implementing the method in your Swift class like this:
func handleNewMessageArrived(messageContent: [NSObject : AnyObject]!) {
// Handle the message
}

In case of Swift 3, this is what you will need
func handleNewMessageArrived(messageContent: [AnyHashable : Any]!) {
// Handle the message
}

Related

Method cannot be a member of an #objc protocol after i remove tuple

I am trying to use Swift protocol in Objective-C.
Firstly it was using tuple like this:
protocol Validation {
func validate(value:String?) -> (Bool, ValidationErrorType)
}
and because tuples are not suitable for Objective-C i decide to use Dictionary for that.
#objc protocol Validation {
func validate(value:String?) -> [NSNumber : ValidationErrorType]
}
And the result is :
Method cannot be a member of an #objc protocol because its result type cannot be represented in Objective-C
Could you please share you're opinion about what i am doing wrong ?
The method have ValidationErrorType as a result with Dictionary, and that's I think preventing you from bridging the protocol. To solve the problem you have to make it objc compatible or change the return value to directly NSDictionary like this.
#objc protocol Validation {
func validate(value:String?) -> NSDictionary
}

How to define optional methods in a Swift protocol with Swift parameters?

TL;DR
How can I define optional methods in a swift protocol that accept custom typed parameters?
The case
I understand that the way to define optional methods in a swift protocol is using the #objc flag. Like so:
#objc protocol someSweetProtocol {
optional func doSomethingCool()
}
But when I wanted to use my custom type for the parameter, like so:
#objc protocol someSweetProtocol {
optional func doSomethingCool(🚶🏼: HSCoolPerson)
}
I got this error:
Which is not cool.
How can this problem be solved? Also can you explain why this is happening?
Addendum
This is how HSCoolPerson is defined:
class HSCoolPerson {
...
...
...
}
Nothing special there...
The problem is this:
class HSCoolPerson {
// ...
}
As the error message plainly tells you, that type, the class HSCoolPerson, is completely invisible to Objective-C. And a protocol optional method is an Objective-C language feature; Swift merely borrows it, as it were. (That's why you have to say #objc protocol to get this feature.) So any time you want to define a protocol optional method, you have to do it in a way that Objective-C can understand, because it is Objective-C that is going to do the work for you.
To expose this class to Objective-C, simply derive it from NSObject:
class HSCoolPerson : NSObject {
// ...
}
Problem solved.
Put the default implementations in an extension, like so:
class HSCoolPerson {}
protocol SomeSweetProtocol {
func doSomethingCool()
}
extension SomeSweetProtocol {
func doSomethingCool(🚶🏼: HSCoolPerson) {
// default implementation here
}
}
class SomeSweetClass: SomeSweetProtocol {
// no implementation of doSomethingCool(_:) here, and no errors
}
you can declare func like that in protocol
#objc optional func doSomethingCool(🚶🏼: HSCoolPerson)

How does one specific a protocol in a function parameter?

I'm writing a factory class that is trying to work with custom protocol defined functions. The compiler throws an error, because I don't know how to add a protocol definition to a function parameter.
Example:
protocol MyCustomFunctions {
func customFunction()
}
class MyVC: UIViewController, MyCustomFunctions {
func customFunction() {}
}
class Factory {
func createButton(specificVC: UIViewController) // need protocol here
{
specificVC.customFunction() // error thrown
}
}
How can one specific a protocol during a variable definition?
Or is there another way?
First of all ,convention says classes start with a Capital letter.
class MyVC: UIViewController, MyCustomFunctions {
func customFunction() {}
}
Then what you need is the correct type in the argument
class factory: NSObject {
func createButton(specificVC: MyVC) // you need a class that conforms to protocol here.
{
specificVC.customFunction() // no error anymore
}
}
You have another option. You can simply promise in the argument that you won't disclose the full type of the object ,you will only say it's an opaque object that conforms to protocol.
class factory: NSObject {
func createButton(specificVC: MyCustomFunctions) // you need a class that conforms to protocol here.
{
specificVC.customFunction() // no error anymore
}
}
BONUS:
The way you could have reasoned about this and find an answer is this>
Error is thrown when I call specificVC.customFunction()...Hmmm...so this object can only run this function if it is of type that actually HAS the function. So let's take a look at the argument type - UIViewController - ..UIViewController certainly doesn't have this function. It's the MyVC or the Protocol.
Type safety in Swift is very strict. Just "follow the type flow" and you will be good.

Not Conforming to the Delegate in Swift

I have a protocol DataProviderDelegate which is defined below:
protocol DataProviderDelegate : class {
typealias Object
}
Now, I have a class which inherits this protocol as shown below:
extension ShoppingListTableViewController : DataProviderDelegate {
}
The error is that the ShoppingListTableViewController does not conform to the DataProviderDelegate protocol. I can see that I have not implemented the Object typealias but if it is required how do I do that?
You can try add this line in ShoppingListTableViewController hope this can help you :)
typealias Object = AnyObject

Swift class in Objective-C project (Compiler error)

I created an Swift class in my Objective-C project. There are no problems with the generated bridging interfaces between objective-c and swift.
In my objective-c project, I have an class named Task, its Task.h looks like following:
#interface Task: NSObject
…
- (id) initWithHomeworks:(NSDictionary *)homeworks
#end
The Task.m looks like this:
#implementation Task
- (id) initWithHomeworks:(NSDictionary *)settings {
self = [super init];
//Do something with self...
...
return self
}
My swift code inherits the above class:
import Foundation
class SubTask : Task {
//Compiler Error 1
func initWithHomeworks(homeworks: Dictionary<String, String>) -> AnyObject{
//Compiler Error 2
return super.initWithSettings(settings)
}
}
I get two compiler errors in the place commented above. The error messages are below:
Compiler Error 1:
Method ‘initWithHomeworks’ with Objective-C selector ‘initWithHomeworks:’ conflicts with initializer ‘init(homework:)’ from superclass ‘Task’ with the same Objective-C selector
(I haven't declared any method init(homework:))
Compiler Error 2:
‘Task’ does not have a member named ‘initWithHomeworks’
Why I get these two errors in my Swift class? How to fix them?
The fundamental reason for that you are seeing is that Swift converts Objective-C methods names intelligently. From the docs:
To instantiate an Objective-C class in Swift, you call one of its
initializers with Swift syntax. When Objective-C init methods come
over to Swift, they take on native Swift initializer syntax. The
“init” prefix gets sliced off and becomes a keyword to indicate that
the method is an initializer. For init methods that begin with
“initWith,” the “With” also gets sliced off. The first letter of the
selector piece that had “init” or “initWith” split off from it becomes
lowercase, and that selector piece is treated as the name of the first
argument. The rest of the selector pieces also correspond to argument
names. Each selector piece goes inside the parentheses and is required
at the call site.
In your case the Objective-C initWithHomeworks:(NSDictionary *)homeworks method is converted to Swift as init(homeworks: [NSObject : AnyObject]!). You can override it as follows:
Given an Objective-C header:
#interface Task : NSObject
- (id)initWithHomeworks:(NSDictionary *)homeworks;
#end
Swift subclass:
class SubTask : Task {
override init!(homeworks: [NSObject : AnyObject]!) {
super.init(homeworks: homeworks)
}
}
This answer was completed using Swift 1.2 in Xcode 6.4
Update based on comments
You have defined your SubTask's initialiser as a regular function:
func initWithHomeworks(homeworks: Dictionary<String, String>) -> AnyObject{
return super.initWithSettings(settings)
}
This is incorrect for the following reasons:-
func is not allowed on init methods
init methods shouldn't declare a return type, remove -> AnyObject
init methods don't return anything, remove the return keyword from the super.init...
Swift initialisers do not return a value however you can still assign the result to a variable:
Swift:
var mySubTask = SubTask(homeworks: someDictionary)
Objective-C:
SubTask *mySubTask = [[SubTask alloc] initWithHomeworks:someDictionary];
If you want to override init method,you should write it like this
class SubTask:Task{
override init!(homeworks: [NSObject : AnyObject]!) {
super.init(homeworks: homeworks)
}
}

Resources