Objc Protocol Implementation in Swift

Importing a Swift protocol in Objective-C class

You need to add the @objc attribute to your Swift protocol like so:

@objc protocol AnalyticProtocol {

}

swift, objective-c protocol implementation

The answer is:

func webSocket(webSocket: SRWebSocket!, didReceiveMessage message: AnyObject!)

see

Functions in Swift Reference Book

Method name in Obj-C webSocket:didReceiveMessage is translated such as the first part is the method name, the other parts are the external parameter names (didReceiveMessage). Also note that id becomes AnyObject and Obj-C references are translated with ! as implicitly unwrapped optionals (this is no longer true, implicitly unwrapped optionals are now rare thanks to attributes added to Obj-C declarations).

Implementing Objective-C protocol in Swift class

Generally, in Swift you have to implement ALL methods of a protocol. (See this question about optional protocol methods: How to define optional methods in Swift protocol?)

But as you said, the framework is written in Objective-C. Objective-C supports optional methods in protocols.

@protocol ProtocolName
@required
// list of required methods
@optional
// list of optional methods
@end

Source


That's why you don't necessarily need to implement all methods declared in a protocol. Usually, only the most important methods are marked with @required, because when calling an optional method, you should always check, if the delegate implemented it.

Implement Objective c protocol in Swift

There are two errors in the delegate method

func uploadProgressPercentage(percentage:Int?){
println(percentage)
}

The parameter must not be an optional, and the C type int is mapped to Swift
as CInt (an alias for Int32):

func uploadProgressPercentage(percentage:CInt){
println(percentage)
}

Alternatively, you could use NSInteger in the Objective-C protocol, which is
mapped to Int in Swift. This would be a 32-bit or 64-bit integer, depending
on the architecture, whereas int/CInt is always 32-bit.

How to implement objective C protocol in swift class?

Add this line in the bridging header

#import "BDViewController.h"

maybe it will solve your problem. Let me know if it is helpful.

Swift protocol extension in Objective-C class

Objective-C protocols cannot have default implementations.

Objective-C protocols can have real optional methods/properties, unlike Swift protocols, which only have required methods/properties. The workaround for this in Swift is the use of a default implementation, however, sadly those cannot be seen in Objective-C.

I would suggest creating a pure Swift protocol and for all Objective-C classes that want to extend this, write the conformance in Swift, then create @objc wrapper functions in Swift that call the default protocol implementations - if it needs to be called, if it doesn't need to be called, simply ignore it.

Something along the lines of:

protocol SwiftProtocol {
func requiredFunc()
func optionalFunc()
}

extension SwiftProtocol {
func optionalFunc() {}
}

@objc extension ObjcClass: SwiftProtocol {
@objc func requiredFunc() {
print("do something")
}

// This will call the default implementation - can be omitted if you don't need to call the default implementation from Objective-C
@objc func objc_optionalFunc() {
optionalFunc()
}
}

Using an implementation of a Swift protocol within Obj-C

In Objective-C, a protocol is not a type. You should declare your protocol-conforming class like so:

id<TheProtocol> p = [[ObjCClass alloc] init];

The reason why your forward declaration compiled is because that's what forward declarations do - they announce to the compiler that a class exists and that the linker will fill it in later in the build process.

(That's why changing to id p =... works too.)

In Swift, we declare classes with something like:

class MyClass : Superclass, Protocol, AnotherProtocol { ... }

In Objective-C we use this:

@class MyClass : SuperClass <Protocol, AnotherProtocol>
// ...
@end

See the difference? In Swift, protocols and the superclass are mixed into the inheritance declaration, whereas Objective-C treats them very differently.

Protocols and Classes are treated slightly different across the two languages, thus used differently.

id in ObjectiveC is analogous to AnyObject? in Swift. An object which conforms to SomeProtocol is obviously AnyObject or id in Objective-C.

Implement protocol partially in Objective C and partially in Swift

When building a project that has mixed Swift+Objective-C code, this is a brief summary of what happens:

  1. the bridging header is processed
  2. the Swift files are compiled
  3. the Objective-C files are compiled

The error you see occurs at step #2, at this point the compiler sees that the Objective-C class conforms to UITableViewDataSource, thus it assumes that the Objective-C code implements the tableView(_:numberOfRowsInSection:) method, thus it sees a conflict since the Swift code also implements the method.

The source of the problem is the fact that you are trying to implement some of the protocol methods in Objective-C, and some in Swift, and this is not possible, you need to either implement all the non-optional methods of the protocol either in Swift, or Objective-C.

If you really want to go this road, a possible solution would be to move the protocol conformance on the Swift side, and declare all the other methods in the Objective-C header as public methods of that class. But this might cause other problems along the way.

Swift protocol in Objective-C class

There are two common reasons for this occuring:

  1. Getting the module name wrong, see my answer.
  2. Having a circular reference - see mitrenegades answer below.

1. Get the module name right:

If both the swift protocol and and Objective C are in the same project then according to apple you should just need to make sure you get the correct module name.

For Xcode6 beta 5 you can find it under BuildSettings->Packaging->Product Module Name

A common mistake would be to think that each swift file/class gets its own file, but instead they are all put into one big one that is the name of the project.

A further mistakes are if the module name has spaces, these should be replaced with underscores.

Edit:

With your protocol I created a test project called 'Test' which compiles perfectly and it has the files:

TestObjClass.h

#import <Foundation/Foundation.h>
#import "Test-Swift.h"

@interface TestObjCClass : NSObject <SearcherProtocol>

@end

TestObjClass.m

#import "TestObjCClass.h"

@implementation TestObjCClass

@end

TestProtocol.swift

import Foundation

@objc protocol SearcherProtocol
{
var searchNotificationTarget: SearchCompletedProtocol? { get }
var lastSearchResults: [AnyObject] { get set }

func search(searchParam: String, error: NSErrorPointer) -> Bool
}

@objc protocol SearchCompletedProtocol
{
func searchCompletedNotification(sender: AnyObject!)
}

2. Avoid circular reference:

Mitrenegades answer explains this, but if your project needs to use the explicit objc class that uses the swift protocol, (rather than just using the protocol) then you will have circularity issues. The reason is that the swift protocol is defined to the swift-objc header, then to your obj-c class definition, which then goes again to the swift-objc header.

Mitrenegades solution is to use an objective-c protocol, is one way, but if you want a swift protocol, then the other would be to refactor the code so as to not use the objective-c class directly, but instead use the protocol (e.g. some protocol based factory pattern). Either way may be appropriate for your purposes.

Add Swift protocol conformance to Objective-C header and make it public

In pure objective-c, you cannot make a class conform to a protocol without importing it in the header. To make the use of a protocol private, the conformance shouldn't be declared in the header. It remains possible to call such a method using a cast however, but it should be done with caution because it's a little bit unsafe :

if ([anInstance respondToSelector:@selector(myProtocolMethod)])
[(id<MyProtocol>)anInstance myProtocolMethod];

I'm not familiar with Swift, but I think you can do the same this way (or something close to it) :

 if let conformingInstance = anInstance as? MyProtocol
conformingInstance.myProtocolMethod

EDIT : To complete my first assertion, forward declarations can still be used in the header when you need to declare a method receiving or returning an instance conforming to that protocol :

@SomeProtocol;

// This is not possible
@interface MyClass : NSObject <SomeProtocol>

// But this is possible
@property (nonatomic) id<SomeProtocol> someProperty;
-(void) someMethod:(id<SomeProtocol>)object;
@end

In this document Apple clearly said that :

Forward declarations of Swift classes and protocols can be used only
as types for method and property declarations.

So it seems that the rule is the same whatever the protocol is an Objective-c protocol or a Swift protocol.



Related Topics



Leave a reply



Submit