In Objective C we can declare a delegate this way
#property (nonatomic, weak) id<SomeProtocol> delegate
and in swift
weak var delegate : SomeProtocol?
but in Objective C we can force the delegate to be of a certain class:
#property (nonatomic, weak) UIViewController<SomeProtocol> delegate
how i do this in swift?
Swift requires you to know the size of the type at compile time, so you would need to make your class generic to your delegate type:
protocol SomeProtocol: class {}
class SomeClass<T: UIViewController> where T: SomeProtocol {
weak var delegate : T?
}
There's another option, if you really don't care about it being constrained to a certain type, but to a certain interface, you could describe the UIViewController via another protocol that exposes the methods you need of it.
protocol UIViewControllerProtocol: class,
NSObjectProtocol,
UIResponderStandardEditActions,
NSCoding,
UIAppearanceContainer,
UITraitEnvironment,
UIContentContainer,
UIFocusEnvironment {
var view: UIView! { get set }
func loadView()
func loadViewIfNeeded()
var viewIfLoaded: UIView? { get }
}
extension UIViewController: UIViewControllerProtocol {}
protocol SomeProtocol: class {}
class SomeClass {
weak var delegate : SomeProtocol & UIViewControllerProtocol?
}
This will let you use many of the methods and properties in a UIViewController, but it doesn't really constraint your delegate to be a UIViewController because any other object could implement this protocol and be used instead.
PS: this is Swift 3.0
Related
I have created on Class in Swift and that class and its protocol I am using in Obj-C enabled project but I am getting below error while compiling my project.
cannot find protocol declaration for 'SpeechRecognizerDelegate'; did
you mean 'SFSpeechRecognizerDelegate'?
Can anyone guide me on this how can I use Swift class protocol in my Obj-C class.
Here is my Swift code:
protocol SpeechRecognizerDelegate : class {
func speechRecognitionFinished(_ transcription:String)
func speechRecognitionError(_ error:Error)
}
class SpeechRecognizer: NSObject, SFSpeechRecognizerDelegate {
open weak var delegate: SpeechRecognizerDelegate?
}
Protocol use in Obj-C:
#import "ARBot-Swift.h"
#interface ChatScreenViewController : JSQMessagesViewController <SpeechRecognizerDelegate>
Let me know if required more info.
Thanks in Advance.
in Swift:
#objc public protocol YOURSwiftDelegate {
func viewReceiptPhoto()
func amountPicked(selected: Int)
}
class YourClass: NSObject {
weak var delegat: YOURSwiftDelegate?
}
in Objective-C headerFile.h
#protocol YOURSwiftDelegate;
#interface YOURController : UIViewController < YOURSwiftDelegate >
in Objective-C Implementation.m
SwiftObject * swiftObject = [SwiftObject alloc] init];
swiftObject.delegate = self
Define your Swift protocol like this inside your Swift file.
#objc protocol SpeechRecognizerDelegate: class{
func speechRecognitionFinished(_ transcription:String)
func speechRecognitionError(_ error:Error)
}
Create a Swift Module inside your project setting then use it. You can find here complete blog for the mix language coding.
Then use Protocol inside Objective C class,
We required to add protocol inside Objective C file -
#import "ARBot-Swift.h"
#interface ChatScreenViewController : JSQMessagesViewController <SpeechRecognizerDelegate>
Then you need to conform to the protocol methods -
- (void)viewDidLoad {
[super viewDidLoad];
SpeechRecognizer * speechRecognizer = [[SpeechRecognizer alloc] init];
speechRecognizer.delegate = self;
}
#pragma mark - Delegate Methods
-(void)speechRecognitionFinished:(NSString *) transcription{
//Do something here
}
-(void)speechRecognitionError:(NSError *) error{
//Do something here
}
I had a similar issue after following (import header + Objc annotation on protocol). I got the warning when using Swift code from Objective C headers. Solved by only importing into the implementation .m files.
Add #objc attribute to your protocol:
#objc protocol SpeechRecognizerDelegate : class {
//...
}
Include Swift Classes in Objective-C Headers Using Forward Declarations
//MySwiftClass.swift
#objc protocol MySwiftProtocol {}
#objcMembers class MySwiftClass {}
// MyObjcClass.h
#class MySwiftClass;
#protocol MySwiftProtocol;
#interface MyObjcClass : NSObject
- (MySwiftClass *)returnSwiftClassInstance;
- (id <MySwiftProtocol>)returnInstanceAdoptingSwiftProtocol;
// ...
#end
I have an Objective C class which has the following property:
#property (nonatomic, strong, readonly) dispatch_queue_t couchDispatchQueue;
I have a Swift extension of that class where I reference that property like so:
couchDispatchQueue.async {
When I do that, I get the following compiler warning:
Property type 'OS_dispatch_queue * _Nullable' is incompatible with type 'dispatch_queue_t _Nullable' (aka 'NSObject *') inherited from 'BZCouchDatabase'
I can see why, since my app's generated App-Swift.h file has:
#property (nonatomic, readonly, strong) OS_dispatch_queue * _Nullable couchDispatchQueue;
while dispatch_queue_tis defined as:
typedef NSObject<OS_dispatch_queue> *dispatch_queue_t;
Edit
I've figured out the "further complication" that I was missing in my original description. This property is required by an Objective C protocol which also requires inheritance from NSObject. As soon as I make the Swift class inherit from NSObject and conform to the objective C protocol, I get the warning. The following sample code is enough to set off the warning:
Objective C:
#protocol Thingness
#property (nonatomic, strong, readonly, nullable) dispatch_queue_t couchDispatchQueue;
#end
Swift:
class Thing: NSObject, Thingness {
var couchDispatchQueue: DispatchQueue?
}
My question still is: is it safe for me to just silence this warning? Should I file a radar?
Very well described situation — but I can't reproduce it. When I declare
#property (nonatomic, strong, readonly) dispatch_queue_t couchDispatchQueue;
in an Objective-C class file, the generated header shows me
open var couchDispatchQueue: DispatchQueue! { get }
This is thus seen as a normal Swift 3 DispatchQueue, and my call to couchDispatchQueue.async produces no warning at all.
To be clear, I tried it two ways. I declared the couchDispatchQueue property in the .h file for a Thing class. I imported Thing.h into Swift. I then wrote this code in Swift:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
Thing().couchDispatchQueue.async {}
}
}
extension Thing {
func test() {
self.couchDispatchQueue.async {}
}
}
Neither in the straight instance method call nor in the extension do I see any warning.
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.
I am new to Swift. I've taken a couple of online course and have started converting an existing Objective-C project to Swift as a learning experience. I have a few questions if someone has time. I've searched the board but haven't found the answers. I am sorry if I missed them.
Delegate Protocols - I'm used to defining my own in Objective-C. Below I have the original Objective-C version and below it I have my new Swift version. Have I followed the correct design pattern for Swift?
I find myself making optionals for all of the properties especially objects like NSData or custom classes. Is this practice acceptable? I am not sure how I would know an initial value for most objects. I know the language wants you to set an initial value but it seems strange for certain objects.
If I am not mistaken we do not have to call self.super init in custom initializers in Swift. Is this correct?
Objective-C Version
#protocol FLOParserHandlerDelegate;
#interface FLOParserHandler: NSObject <NSXMLParserDelegate>
// Properties
#property (nonatomic, strong) NSMutableData *PHData;
#property (nonatomic, strong) NSMutableString *currentParsedCharacterData; // This grabs the characters as they come in and adds them together.
#property (nonatomic, strong) NSMutableArray *XMLDataArray; // This is the master array that holds all of the article arrays with the date, title and link objects.
#property (nonatomic, strong) NSMutableDictionary *dateTitleLinkDictionary;// This is used to gather the date, title and link in an array to added to the master array.
// Delegate Property
#property (nonatomic, weak) id <FLOParserHandlerDelegate> delegate;
// init Methods
- (id) initWithCHData: (NSMutableData *) data;
// Class Methods
-(void) startParser;
#end
#pragma mark-
#pragma mark FLOParserHandler Protocol Definition
#protocol FLOParserHandlerDelegate
#optional
- (void) floParserHandlerDidFinishParsing: (FLOParserHandler *) parserHandler;
- (void) floParserHandler: (FLOParserHandler *) parserHandler didFailWithError: (NSError *) error;
#end
Swift Version
import Foundation
protocol FLOParserHandlerDelegate
{
func floParserHandlerDidFinishParsing(parserHandler : FLOParserHandler) -> ()
func floParserHandler(parserHandler : FLOParserHandler, error : NSError) -> ()
}
// Note that we have to inherit from NSObject here. I believe this iis because we are mixing it with Objective-C.
class FLOParserHandler : NSObject, NSXMLParserDelegate
{
var PHData : NSData?
var currentParsedCharacterData : String?
var XMLDataArray : [String]?
var dateDictionary : [String:NSDate]?
var titleDictionary : [String:String]?
var linkDictionary : [String:String]?
// Delegate Property
var delegate : FLOParserHandlerDelegate?
// Init Methods
init(data : NSData)
{
self.PHData = data
}
// Class Methds
func startParser()
{
var parser = NSXMLParser(data: self.PHData)
parser.delegate = self
parser.parse()
}
}
Thank you,
Jon
Your protocol definition is valid. There is one little thing you should know about:
As with type property requirements, you always prefix type method
requirements with the class keyword when they are defined in a
protocol
protocol SomeProtocol {
class func someTypeMethod()
}
Its perfectly fine to use optionals, or you may use implicity unwrapped optionals like NSData!. In which case you should do this and where no, you may read here: Why create "Implicitly Unwrapped Optionals"?.
Shortly, you doing this in following situations:
a) Constant cannot be defined using initializtion, but you know that it would not be nil (otherwise app will crash)
b) Objective-C Api required you to use pointers, and pointers in Obj-C could be nil. In that case you use imilicity unwrapped optionals.
You always have to call 'super' if you have superclass, to be sure, that class is properly initialized.
Hope that helps.
I'm working on converting my project from Objective-c to Swift, and a Swift class I'm using, I have a protocol I'm trying to access in an Objective-c class. My problem is, the delegate is not accessible in the objective-c class. Here is my swift class:
protocol RateButtonDelegate {
func rateButtonPressed(rating: Int)
}
class RateButtonView: UIView {
var delegate: RateButtonDelegate?
var divider1: UIView!
var divider2: UIView!
}
When I look at the MyProject-Swift.h file, I don't see the delegate:
#interface RateButtonViewTest : UIView
#property (nonatomic) UIView * divider1;
#property (nonatomic) UIView * divider2;
#end
and when I try to use rateButtonView.delegate in my Objective-c class, I get a compiler error.
Anyone know the issue? How do access a Swift protocol in Objective-c?
You need to mark your protocol with the #objc attribute for it to be accessible from Objective-C:
#objc protocol RateButtonDelegate {
func rateButtonPressed(rating: Int)
}
This page from Apple's documentation covers the issue.