When overriding in a Swift subclass of an Objective-C class, I get a message saying:
Property type 'BOOL' (aka 'bool') is incompatible with type 'Boolean' (aka 'unsigned char') inherited from 'ChildClass'
I tried to use Other Boolean types but it won't work.
Any idea how to properly override an Objc BOOL in Swift
Swift code (subclass):
override var myVar: Bool {
get {
return something ? true : myVar
}
set {
myVar = newValue
}
}
Objc Parent Declaration:
#property(atomic) Boolean isLoading;
Swift bridging header where the warning appear:
SWIFT_CLASS("_TtC6Module30ChildClass")
#interface ChildClass : ParentClass
#property (nonatomic) BOOL myVar; //<----- Here
#end
in ObjC BOOL and bool are not the same (BOOL is a signed char, whereas bool - aka C bool- is an unsigned char). Boolean is typedef to unsigned char as well, so is a C bool.
Can you change your objC property to BOOL?
if not, then use the swift type 'CBool'.
https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html
Related
I can't bridge ObjectiveC long type into Swift.
//Swift
typealias Long = Int64
struct Item: Equatable {
let itemId: Long
...
}
//ObjC
#interface MyObject : NSObject
#property(nonatomic, assign) long itemId;
//Try create object in Swift
Item(itemId: objCObject.itemId)
Error:
Cannot convert value of type 'Int' to expected argument type 'Long' (aka 'Int64')
The (Objective-)C type long is bridged to Swift as CLong which is an alias for the Swift Int type. Int can be a 32-bit or 64-bit integer, depending on the platform.
In any case, you cannot cast or assign an Int64 directly to an Int, see also Can I cast Int64 directly into Int?.
If you want to keep the Swift itemID as a Int64 then you'll have to convert it to CLong when calling the Objective-C method. Alternatively you can change the Swift type to make it compatible:
struct Item: Equatable {
let itemId: CLong
...
}
Another option would be to change the Objective-C type to
#property(nonatomic, assign) int64_t itemId;
which is then imported to Swift as Int64.
property block getting nil I have objective-c viewcontroller class which has a property block in
// UAEPassWebViewController.h
#property (nonatomic, copy) void (^onUAEPassSuccessBlock)(NSString *response);
#property (nonatomic, copy) void (^onUAEPassFailureBlock)(NSString *response);
I had made the bridging-header.h class and trying to call code in swift class like below
webVC.onUAEPassSuccessBlock = { (code: String) in
print(code)
if (code != "") {
self.showHud()
self.getUaePassTokenForCode(code)
}
} as? (String?) -> Void
but onUAEPassSuccessBlock property getting nil when executing code in
// UAEPassWebViewController.m
if(_onUAEPassSuccessBlock && code) {
_onUAEPassSuccessBlock(code);
[self.navigationController popViewControllerAnimated:true];
}
this is only happens when I am calling from swift class. if I call the same property from objective-c class the below is the code it worked fine.
// ViewController.m
webVC.onUAEPassSuccessBlock = ^(NSString *code) {
if(code) {
[self showLoadingIndicator];
[self getUaePassTokenForCode:code];
}
};
anyone can help me please
The value is nil because that's what you requested when you added as? (String?) -> Void. This says "if it's not possible to convert this to the given type, then return nil." It's not possible to convert this function to the correct type, so it's nil.
The function you've written is (String) -> Void. You cannot implicitly convert that to (String?) -> Void. What would the first function do if it received nil?
Rewrite your ObjC to not allow nil in this position using _Nonnull:
#property (nonatomic, copy) void (^onUAEPassSuccessBlock)(NSString * _Nonnull response);
Or rewrite the function to accept String?:
webVC.onUAEPassSuccessBlock = { (code: String?) in
...
I have the following Objective-C class which uses an Objective-C enum:
MyClass.h:
typedef NS_ENUM(NSInteger, MyEnum) {
MyEnumCase1
};
#interface MyClass : NSObject
-(void)method:(MyEnum)param;
#end
MyClass.m:
#implementation MyClass
-(void)method:(MyEnum)param {}
#end
I can subclass MyClass in Swift and override the method like this:
SubClass.swift
class SubClass: MyClass {
override func method(_ param: MyEnum) {}
}
But if I define the enum in Swift instead of in Objective-C, overriding the method fails:
MyClass.h:
// Forward declare the enum in Objective-C
typedef NS_ENUM(NSInteger, MyEnum);
#interface MyClass : NSObject
-(void)method:(MyEnum)param;
#end
SubClass.swift:
#objc enum MyEnum: NSInteger {
case case1
}
class SubClass: MyClass {
override func method(_ param: MyEnum) {} // Error
}
In this case, overriding the method fails with the error
Method does not override any method from its superclass
The enum itself works in Swift, I can add the following method to SubClass, and it compiles:
func useEnum() {
let x = MyEnum.case1
}
Why does the overriding fail?
When I opened the Generated Interface of MyClass.h, Xcode showed something like this:
import Foundation
open class MyClass : NSObject {
}
Nothing more but comments.
Seems Swift cannot import incomplete enums, so methods which use such types are not imported neither.
So, your #objc enum MyEnum just declares a new enum type, and override func method(_ param: MyEnum) is an attempt to override a method which does not exist in its superclass, from the Swift side.
The enum itself works in Swift
Of course. The enum works even if you removed the line of typedef (with all lines using it) from MyClass.h .
The enum works even if you specify some different type than NSInteger:
#objc enum MyEnum: UInt8 {
case case1
}
Seems you cannot write an actual definition of an enum in Swift, which is declared as an incomplete enum in Objective-C.
I'm trying to pass a Swift function (with multiple parameters, defined as a closure) to an Objective-C function. Technically, the function is defined in Objective-C++, but I'm encountering an issue at the header level, so it should be equivalent for this question.
In the Objective-C header, I have this defined as:
#interface MyObjCClass : NSObject
typedef void (^MyCallback)(NSMutableData*, int);
- (void) functionThatTakesACallback: (MyCallback) callback;
In swift, I'm trying to use it in this way:
self.objcclass!.functionThatTakesACallback()
{
(values: NSMutableData, length: Int32) -> Void in
// Do something with this data.
}
The error I get is:
Cannot convert value of type '(NSMutableData, Int32) -> Void' to expected argument type 'MyCallback!'
If I unwrap that a bit, by putting the block directly into the Objective-C function definition (sans typedef):
- (void) functionThatTakesACallback: (void (^)(NSMutableData*, int)) callback;
it gives me the vaguely more helpful:
Cannot convert value of type '(NSMutableData, Int32) -> Void' to expected argument type '((NSMutableData!, Int32) -> Void)!'
So, essentially, is there any way to unwrap this closure to fit the expected type? Or redefine the Objective-C type?
I think you'll need to add nullability attributes to your callback parameter and to the callback argument for your function. There are two ways you could do it.
Add the nullability annotations to each place that needs it.
#interface MyObjCClass : NSObject
typedef void (^MyCallback)(nonnull NSMutableData*, int);
- (void) functionThatTakesACallback: (nonnull MyCallback) callback;
Set the whole file to assume nonnull
NS_ASSUME_NONNULL_BEGIN
#interface MyObjCClass : NSObject
typedef void (^MyCallback)(NSMutableData*, int);
- (void) functionThatTakesACallback: (MyCallback) callback;
#end
NS_ASSUME_NONNULL_END
I actually just managed to fix this, but because the solution is simple but rather non-intuitive given the error message, here is the solution:
The function call from Swift must actually be:
self.objcclass!.functionThatTakesACallback()
{
(values: NSMutableData!, length: Int32!) -> Void in
// Do something with this data.
}
For the parameter values Objective-C is expecting a pointer to an object and that pointer could be nil. In Swift that translates to an optional value. An optional is followed by a ? and should be unwrapped - checked for nil and if there's an object there then return it.
Try:
self.objcclass!.functionThatTakesACallback() {
(values: NSMutableData?, length: Int32) -> Void in
if let values = values { // first values is a local, second values is unwrapped into it
// Do something with this data.
}
}
I have some Obj-C code in which I have a class with many blocks as members.
The property in question is the following:
#property(nonatomic, readonly, retain) BOOL(^truthPredicate)(int, NSMutableDictionary*);
And is implemented in a #synthesize statement in the .m file. In one of the init methods for the class, I tried to set the property to a literal block:
truthPredicate=^(int val, NSMutableDictionary* params) {return val >= MANodeTruthThreshold ? YES : NO;};
This signals a compiler error. The compiler, despite the fact that YES and NO are defined to be (BOOL)1 and (BOOL)0, and BOOL being defined as signed char, the compiler insists that I'm trying to assign an int returning block to a BOOL returning variable. How do I make Obj-C realize that I'm returning BOOLs, not ints?
Apparently, type inference is failing you. Try the more verbose syntax:
truthPredicate=^ BOOL (int val, NSMutableDictionary* params) {return val >= MANodeTruthThreshold ? YES : NO;};