This is how it is defined in objective-c:
#interface AFHTTPRequestOperation : AFURLConnectionOperation
#property (readonly, nonatomic, strong) id responseObject;
How to assign sth to this property?
I would like to mock this property for later usage. So I need there my own responseObject overriden in Swift. Any ideas how to do this? I can subclass, extend or whatever. The only thing is it must by type of AFHTTPRequestOperation.
class MyRequestOperation: AFHTTPRequestOperation {
override var responseObject: [String: AnyObject]
}
It produces an error:
Getter for responseObject with Objective-C selector responseObject conflicts with getter for responseObject from superclass AHTTPRequestOperation with the same Objective-C selector
So, the answer is simple as #Atul Mishra said:
class MyRequestOperation: AFHTTPRequestOperation {
var myOverridenResponseObject: AnyObject?
override var responseObject: AnyObject? {
get {
return myOverridenResponseObject
}
set {
myOverridenResponseObject = newValue
}
}
}
You can present an inherited read-only property as a read-write property by providing both a getter and a setter in your subclass property override.but however you cannot provide an inherited read-write property as read-only property.
for better clarification refer https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Inheritance.html#//apple_ref/doc/uid/TP40014097-CH17-XID_300
Related
I am using a Swift class which uses a variable sharedInstance. When I am trying to use this variable in my Objective-C file, I am getting the error:
No known class method for selector 'sharedInstance'
My Swift class:
class SpeakToMeForUnity : NSObject, SFSpeechRecognizerDelegate {
fileprivate var speechRecognizer : SFSpeechRecognizer?
fileprivate var recognitionRequest : SFSpeechAudioBufferRecognitionRequest?
fileprivate var recognitionTask : SFSpeechRecognitionTask?
fileprivate var audioEngine : AVAudioEngine?
static let sharedInstance = SpeakToMeForUnity()
override fileprivate init() {
super.init()
self.speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "ja-JP"))!
self.audioEngine = AVAudioEngine()
self.speechRecognizer?.delegate = self
}
// Some other functions
}
Below is my Objective-C file:
#import <Speech/Speech.h>
#import "SpeakToMeForUnity-Swift.h"
extern "C"
{
void _prepareRecording()
{
SpeakToMeForUnity *instance = [SpeakToMeForUnity sharedInstance];
[instance prepareRecording];
}
void _recordButtonTapped()
{
SpeakToMeForUnity *instance = [SpeakToMeForUnity sharedInstance];
[instance recordButtonTapped];
}
}
I am using Swift 4 and Xcode 10.3.
Normally to make Swift available in Objective-C you just need to import your swift module #import "ProductModuleName-Swift.h", as you're doing.
If you need the swift code in the Objective-C header use #class MySwiftClass; or #protocol MySwiftClass;.
You can force some class or property to be accessible in Objective-C by adding the attribute #objc.
Remember that private or fileprivate access level attributes will not be accessible unless you add the previous attribute.
To expose things to ObjC, you need to mark them #objc. In this case you should add this before class and before the static let.
In previous versions of Swift, inheritance from NSObject automatically implied #objc, but that was removed, and it now needs to be explicit.
I'm trying to create an instance of a singleton class written in Objective-C. I must conform to it's delegate protocol. The Swift implementation looks something like this:
class SomeClass: ManagerDelegate {
let manager = Manager.sharedInstance()
func someFunction(){
manager.delegate = self
}
}
The Objective-C singleton class looks something like this:
// header
#protocol ManagerDelegate <NSObject>
#required
-(void)delegateMethod;
#end
#interface Manager : NSObject {
}
+ (id)sharedInstance;
#property (nonatomic, assign) id delegate;
#end
// class file
+ (id) sharedManager{
static Manager *theSharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
theSharedManager = [[self alloc] init];
});
return theSharedManager;
}
- (void) someInternalMethod{
[delegate delegateMethod];
}
Upon specifying the delegate (manager.delegate = self), I receive the error
Ambiguous reference to member 'delegate'
Is the Objective-C class improperly formed or am I implementing it incorrectly? Am I missing something else?
Your problem is caused by the definition of your sharedInstance method in Objective-C. By declaring it as
+ (id)sharedInstance;
it gets converted to sharedInstance() -> AnyObject! in Swift. Swift then doesn't know which of many potential delegate properties that it can find you mean. If you change your Objective C declaration and implementation to be:
+ (instancetype)sharedInstance;
your problem will go away.
And as #rmaddy points out, your delegate should be weak not assign. If you use assign then delegate will be left as an invalid pointer in the event that the delegate is deallocated.
Also, the use of a delegate with a singleton is a bit contradictory. Given that you will only ever have one instance of the Manager which may be used by a number of other objects and you can only have one active delegate at a time there is the potential for conflicts.
I would suggest that either blocks/closures or NSNotification is a better approach to call backs from a singleton.
Its because whenever you bring instance from objective c code to swift it gives as AnyObject so
let manager = Manager.sharedInstance() //manager is AnyObject due to bridging between objc and swift
gives you AnyObject for manager property. You need to forcefully cast that AnyObject to Manager to use it as manager's instance like below.
class SomeClass: NSObject, ManagerDelegate {
let manager = Manager.sharedInstance() as! Manager //here was your error
func someFunction(){
manager.delegate = self
}
func delegateMethod() {
print("Hello")
}
}
Hope this solves your problem :)
I am looking for a general solution to access:
Obj-C named property getters and named property setters from Swift
Conform to an Objective-C #protocol with readonly properties
Similar to Creating an Objective-C equivalent Getter and Setter in Swift, which is closed, yet does not offer a satisfying answer.
Objective-C to Swift Properties Example:
I have an Objective-C protocol defined with two problematic properties, one with a custom getter isEnabled and another with a private setter exists.
#protocol SomeProtocol <NSObject>
#property (nonatomic, assign, getter = isEnabled) BOOL enabled;
#property (nonatomic, readonly) BOOL exists;
#end
How can I access these Objective-C properties from Swift?
This does not seem to work:
func isEnabled() -> Bool { return self.enabled }
and neither does:
var isEnabled:Bool {
get { }
set { }
}
Straight from the documentation:
Use the #objc(<#name#>) attribute to provide Objective-C names for properties and methods when necessary. For example, you can mark a property called enabled to have a getter named isEnabled in Objective-C like this:
SWIFT
var enabled: Bool {
#objc(isEnabled) get {
/* ... */
}
}
Named Objective-C Getter Property in Swift
var _enabled:Bool = false
var enabled:Bool {
#objc(isEnabled) get {
return self._enabled
}
set(newValue){
_enabled = newValue
}
}
readonly Objective-C Property in Swift
Either
var _exists:Bool = false
private(set) var exists:Bool {
get{
return self._exists
}
set(newValue){
self._exists = newValue
}
}
or
var _exists:Bool = false
var exists:Bool {
get{
return self._exists
}
}
and access self._exists directly since there is no setter.
This Objective-C protocol used to work in Swift 1.1, but now errors in Swift 1.2.
Objective-C Protocol stripped down to the one problematic property:
#protocol ISomePlugin <NSObject>
#property (readonly, getter=getObjects) NSArray * objects;
#end
class SomePlugin: NSObject, ISomePlugin {
var objects: [AnyObject]! = nil
func getObjects() -> [AnyObject]! {
objects = ["Hello", "World"];
return objects;
}
}
Here is the Swift 1.2 error:
Plugin.swift:4:1: error: type 'SomePlugin' does not conform to protocol 'ISomePlugin'
class SomePlugin: NSObject, ISomePlugin {
^
__ObjC.ISomePlugin:2:13: note: protocol requires property 'objects' with type '[AnyObject]!'
#objc var objects: [AnyObject]! { get }
^
Plugin.swift:6:9: note: Objective-C method 'objects' provided by getter for 'objects' does not match the requirement's selector ('getObjects')
var objects: [AnyObject]! = nil
^
If I change the Protocol (which I cannot really do since it is from a third party) to the following, the code compiles fine.
// Plugin workaround
#protocol ISomePlugin <NSObject>
#property (readonly) NSArray * objects;
- (NSArray *) getObjects;
#end
Thanks in advance.
You can implement
#property (readonly, getter=getObjects) NSArray * objects;
as a read-only computed property with an #objc attribute
specifying the Objective-C name.
If you need a stored property as backing store
then you'll have to define that separately.
Example:
class SomePlugin: NSObject, ISomePlugin {
private var _objects: [AnyObject]! = nil
var objects: [AnyObject]! {
#objc(getObjects) get {
_objects = ["Hello", "World"];
return _objects;
}
}
}
I have a ClassA that defines a property:
#interface ClassA : NSObject
#property (nonatomic) CGPoint property;
#end
The implementation doesn't override the accessors.
ClassB overrides the setter to do some additional work:
- (void)setProperty:(CGPoint)property {
[super setProperty:property];
[self someAdditionalWork];
}
In an other method of ClassB I try to set this property via the super setter, to skip the additional work:
- (void)otherMethodInClassB {
// ...
super.property = newValue;
// ...
}
When I do this, the KVO notifications for the property are not sent. If I do the same thing, but use self, the KVO notifications work as expected:
- (void)otherMethodInClassB {
// ...
self.property = newValue;
// ...
}
What's going on here? Is this the expected behavior? I couldn't find anything that would say so.
I'm not sure if this is documented, but this is the expected behavior.
Automatic KVO notifications work by silently changing your instance's class in runtime from original ClassB to an auto-generated subclass NSKVONotifying_ClassB which overrides all the required setter methods to do those willChange.../didChange... calls for you. By calling super, you effectively skip all that magic and invoke the original setter, which only does bare value assignment.
P.S. This blog post digs into deeper details of this: https://www.mikeash.com/pyblog/friday-qa-2009-01-23.html