Passing a Swift protocol to an Objective-C pointer - objective-c

Using XCode 10.1 / Swift 4.2.
I'm trying to assign an object that conforms to a Swift protocol to an Objective-C pointer. The following code is a minimal example that compiles and works as expected, but it gives me the following warnings:
If assigning to a local variable: Incompatible pointer types initializing 'NSObject<Animal> *__strong' with an expression of type 'id<Animal> _Nullable'
If assigning to a stored property:
Incompatible pointer types assigning to 'NSObject<Animal> *' from 'id<Animal> _Nullable'
Any idea on how to address that warning without just silencing it?
Swift code:
#objc protocol Animal {
var name: String { get }
}
#objc class Pig: NSObject, Animal {
var name: String = "pig"
}
#objc class Cow: NSObject, Animal {
var name: String = "cow"
}
#objc class Farm: NSObject {
static func getAnimal(name: String) -> Animal? {
// return some animal or nil
}
}
Objective-C code:
// This code returns a valid pointer to a Pig object
// that is usable in objective-c, but it also triggers
// the warning described above
NSObject<Animal>* animal = [Farm getAnimalWithName:#"pig"];

Specify that every Animal implementer also implements NSObject's interface: #objc protocol Animal : NSObjectProtocol
You could also change the type of the variable in ObjC to id<Animal>.

Related

multiple return types in optional function

#objc protocol OptionalProtocol: class { // below error during this type
#objc optional func run5() -> (String?, Int?)
}
error: Method cannot be marked #objc because its result type cannot be represented in Objective-C
#objc protocol OptionalProtocol: class { // no error
#objc optional func run5() -> (String?)
}
I am creating an optional function with multiple return types but a single return type is working fine but when I return more than one value it gives above error.
how to fix it.
Thank you
Objective-C doesn't know tuplets.
The second example doesn't return a tuple, (String?) is practically the same as String?.
If you need to return multiple objects to Objective-C wrap the objects in an array, a dictionary or a custom class.

Swift enum in objective c

I have this enum in swift:
#objc enum HomeViewDataType: Int {
case statistics
case allTime
}
and this protocol;
#objc(TCHomeViewDataUpdaterDelegate)
protocol HomeViewDataUpdaterDelegate {
....
func homeViewDataType() -> HomeViewDataType
}
If I ask Xcode to add the protocol stubs automatically it will add the enum keyword inside the return type parenthesis:
- (enum HomeViewDataType)homeViewDataType
{
<code>
}
I never seen this before: (enum HomeViewDataType)
Any idea why?
It works with or without the enum keyword btw.

Call Swift func from Objective-C with parameter

I want to integrate a Swift class into an UIViewController class.
I think I made all settings correct. I have a class rURLTask:NSObject with a function:
#objc public func primer() {
print("primer")
}
In my .swift file and can call it from my Objective-C-class with:
[URLTask primer];
and it prints nicely.
Another function is:
#objc public func ladeURL(url: URL?) {
print("loadURL")
}
but this one I cannot call from Objective-C. I try to write:
NSURL* testURL = [NSURL URLWithString:#"http://www.google.com"];
[URLTask ladeURL:testURL];
I get the error:
No visible #interface for 'rURLTask' declares the selector 'ladeURL:'
I think there is a very basic mistake. Using Objective-C in Swift 3 in another project worked well.
The reason you cannot call
#objc public func ladeURL(url: URL?) {
print("loadURL")
}
by saying
[URLTask ladeURL:testURL];
is that ladeURL: is not the name of this method as far as Objective-C is concerned. That is what the compiler means when it says that "No visible #interface for 'rURLTask' declares the selector ladeURL:".
Its name as far as Objective-C is concerned is ladeURLWithUrl:. That is because you have exposed the url: parameter name as an external label.
If it was important to you to be able to say
[URLTask ladeURL:testURL];
in Objective-C, you could have declared ladeURL like this:
#objc public func ladeURL(_ url: URL?) {
print("loadURL")
}
See the underscore? That hides the external label of the parameter.
Another solution, allowing you to keep the url: external label, would be to declare the Objective-C name as part of the objc attribution:
#objc(ladeURL:) public func ladeURL(url: URL?) {
print("loadURL")
}
That says to the compiler: "I know you would like to translate the name of this method into Objective-C as ladeURLwithUrl:, but don't; translate it as ladeURL: instead."
When you import the class to OC , the name of the method written in swift is translated concatenated with the withParameterType , as prime
method
#objc public func primer() {
print("primer")
}
has no parameters it can be called like this
[URLTask primer];
but this
#objc public func ladeURL(url: URL?) {
print("loadURL")
}
is translated to
[URLTask ladeURLWithUrl:<#NSURL#>];

enum defined in Objc > Declared in Swift > to be used in Objc

I have a situation. I would appreciated if anyone has a solution for this
I have an objC enum say Abc
I declare this in a swift class, say, MySwiftClass.swift as var abc : Abc!
I have created an instance of MySwiftClass (mySwiftClass) in another ObjC class (myObjC.m file)
In myObjC.m, I’m trying to access enum Abc as mySwiftClass.abc.
This is throwing an error - “Property ‘abc’ not found on object of type MySwiftClass *”.
Basically the enum is not added as property in the “ProjectName-Swift.h” file.
What I believe is happening is that when I’m declaring the ObjC enum in Swift class, it is getting converted to a swift enum and hence I’m not able to access it in ObjC file.
Note: Marking the Swift class as #objc did not work.
Numeric Swift optionals cannot be represented in Objective-C, and thus will not be exposed to Objective-C. Declare abc to not be optional and it should be available from Objective-C.
Consider this Objective-C enumeration:
typedef NS_ENUM(NSInteger, Foo) {
FooBar,
FooBaz,
FooQux
};
Then consider this Swift 3 class:
class SomeObject: NSObject {
var foo1: Foo = .bar // this is exposed to Objective-C
var foo2: Foo! = .bar // this is not
}
The non-optional, foo1, will be exposed to Objective-C, whereas the optional, foo2, will not.

How to use a swift class with a generic type in objective c

I have the following swift class with a NumericType T.
#objc class MathStatistics<T: NumericType> : NSObject {
var numbers = [T]()
func sum() -> T? {
if numbers.count == 0 {
return nil
}
var sum = T(0)
for value in numbers {
sum = sum + value
}
return sum
}
}
In swift a initialize the class object as follows:
let statistics = MathStatistics<Double>()
How do I initialize the same object in Objective C?
The following line does not set the numeric type T.
MathStatistics *stats = [[MathStatistics alloc] init];
You can't. As listed in the documentation:
You’ll have access to anything within a class or protocol that’s
marked with the #objc attribute as long as it’s compatible with
Objective-C. This excludes Swift-only features such as those listed
here:
Generics
Tuples
Enumerations defined in Swift
Structures defined in Swift
Top-level functions defined in Swift
Global variables defined in Swift
Typealiases defined in Swift
Swift-style variadics
Nested types
Curried functions
You'd have to get rid of generics in your class. Then you can use it in Objective-C