String! does not conform to protocol 'ExpressibleByStringLiteral' - objective-c

I am trying to use a method that was defined as Objective C method, from a swift file
the method in objective c is defined as
-(instancetype) init:(NSString*)string data:(id)data;
the method name cannot be refactored.
I am trying to invoke it as follows
let myObject = MyObject("MyString",data:["1","2","3"])
in return i am getting the compile error : "String! does not conform to protocol 'ExpressibleByStringLiteral'"
How can I fix it?
EDIT:
MyObject is defined as follows
`#interface MyObject<__covariant Type> : NSObject #end
#implementation
#end`

In Swift 3, ObjC generics are imported as Swift generics. And you always need to specify the type parameter in Swift generics. (And Swift 3 is not yet so refined as to generate appropriate diagnostics...)
let myObject = MyObject<NSString>("MyString",data:["1","2","3"])
worked.

Is your data actually data, or a [String]?

Related

Invoke Swift closure in Objective-C via `id`

This question has been inspired by this one: Swift closure in array becomes nil in Objective-c, which I answered with a workaround using a wrapper class, but I'm still curious as to why one can't call, in Objective-C, a Swift closure passed via id. A simple example follows.
Objective-C code:
// In a header
typedef void (^EmptyBlock)();
#interface MyClassOC : NSObject
-(void)invoke:(id)blk;
#end
// In an implementation (.m) file
#implementation MyClassOC
-(void)invoke:(id)blk {
EmptyBlock emptyBlock = blk;
emptyBlock();
}
#end
No problem providing an Objective-C block:
EmptyBlock block = ^{ puts("In OC empty block..."); };
MyClassOC * myClassOC = [[MyClassOC alloc] init];
[myClassOC invoke:block];
However, the Objective-C code in invoke... can't call a Swift closure passed in via id:
let myClassOC = MyClassOC()
let myBlock : EmptyBlock = {
print("In Swift EmptyBlock...")
}
myClassOC.invoke(myBlock)
I end up with EXC_BAD_ACCESS on this line:
EmptyBlock emptyBlock = blk;
Any idea what's going on here?
The reason is probably the support introduced in Swift 3 for any Swift type to be represented as an opaque object of id type in Objective-C. Read Swift Value Types in Objective-C in this Apple blog post for details. In that you will see that Swift types are passed as _SwiftValue * when the parameter type is id, this is an opaque type.
The argued benefit of this approach is that Swift value types can be stored in Objective-C collections; however the disadvantage is that you cannot convert to an Objective-C compatible value on the Objective-C side. Debug your code and you'll see the block is being passed as a _SwiftValue * and not an Objective-C block type.
Declare the bak parameter to have EmptyBlock type and your code works.
HTH
Because Swift closures and Objective-C blocks are not the same things. Swift automatically converts a closure to an Objective-C block if they see that you are calling a method with an Objective-C block type, but it doesn't do that otherwise. And as CRD's answer mentions, in Swift 3 any Swift value can be represented as an Objective-C object, so even though it sees that it expects an Objective-C object, it still doesn't know you want an Objective-C block because a Swift closure can still be bridged to an opaque object.
The only way I figured out to pass it from Swift and work is something like:
myClassOC.invoke(myBlock as #convention(block) () -> Void)

Calling objective-c method from Swift error

I get an error when I try to call objective-c method from swift.
my objective-c .h class:
#class myType;
#interface myClass : NSObject
- (myType *)myMethod;
then I will create an object form myClass and try to call myMethod in swift (I have declared anObject of type myClass):
let a = anObject.myMethod();
but I get an error:
Value of type 'myClass' has no member 'myMethod'
If I change myType to something else, the error goes away. So it should be a problem of not recognizing myType in swift..
I appreciate any help
#class myType;
is only a "forward declaration" of that class. In order to call the
- (myType *)myMethod;
method from either Objective-C or Swift, the compiler needs to know the
actual interface declaration of that class. So "myType.h" or whatever
file contains
#interface myType : NSObject
// ...
#end
must be included from the bridging header file.
Remark: Class names should start with a capital letter.
turned out the real problem for me was something else!
I had to simply delete the derived data:
Window -> Projects -> Derived Data -> Delete
Clean Project
Quit Xcode
Open Xcode
Build Project
Apparently, using swift I have to these steps more often..

Pass #protocol type in Swift

I have an Objective-C method which takes Protocol* type as parameter.
How can I invoke this method in Swift.
Example:
// In Objective-C
#protocol AProtocol <NSObject>
#end
#interface MyClass : NSObject
+ (id)proxyWithProtocol:(Protocol*)protocol;
#end
// I can call this method with a protocol as parameter
[MyClass proxyWithProtocol:#protocol(AProtocol)];
If I want to use MyClass in Swift by bridging. How can I pass a protocol defined in Objective-C to proxyWithProtocol method. Can I even pass a protocol defined in Swift to this method?
You would pass the Objective-C protocol in like so:
MyClass.proxyWithProtocol(AProtocol)
If you wanted to pass in a Swift protocol, you would have to expose that protocol to Objective-C:
#objc protocol MyProtocol {
func someGreatFunc()
}
// ...
MyClass.proxyWithProtocol(MyProtocol)
In Swift 3, depending on the way the class is bridged to Swift, your function might look like this:
MyClass.proxy(with: AProtocol)
MyClass.proxy(with: MyProtocol)
Although the compiler isn't happy with the location of "with" and may complain.

Swift/ObjC circular import

I am working on an existing large codebase that is predominately Objective-C but is in the process of converting to Swift.
New classes are being implemented in Swift, but some of these classes need to be accessed from existing ObjC code. In an attempt to follow both ObjC and Swift best practices, the new classes do not have a prefix, but are defined with a prefix for ObjC.
/**
Create contrived class that is named XXClassA in ObjC and ClassA in Swift.
*/
#objc(XXClassA) class ClassA: NSObject {
let foo = "bar"
}
So far this has been working great; Swift code uses ClassA() and ObjC uses [[XXClassA alloc] init]. Once all ObjC code that references XXClassA is removed, #objc(XXClassA) can also be removed from the Swift class.
Unfortunately this breaks down if you have an ObjC class reference XXClassA and then the Swift code attempts to use that new class inside of ClassA.
Say I create an ObjC class, named XXClassC and it instantiates itself using an XXClassA (which is really the Swift class ClassA)
//
// XXClassC.h
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
#class XXClassA;
#interface XXClassC : NSObject
-(instancetype)initWithA:(XXClassA *)classA;
#end
NS_ASSUME_NONNULL_END
The circular reference is now in place. If I attempt to use XXClassC from inside of the ClassA, the initializer is not available.
If I redefine ClassA as this instead, all is well again.
class XXClassA: NSObject {
let foo = "bar"
}
I understand why this is happening and the fix I have in place, however I want to continue to use this pattern of prefixed ObjC classes. Any ideas on how to avoid the circular import, but also keep the naming convention?
Full code sample here: https://gist.github.com/justAnotherDev/78483f9d94e40fd90c38
I'm having the same problem. My workaround is:
Use an objc-style prefixed name for the Swift class.
Add a typealias: typealias ClassA = XXClassA.
Always use the unprefixed name from Swift code.
With this pattern it's at least easy to remove the prefix when the last objc dependency is gone.

Implement Objective c protocol in Swift

I have this protocol in a objective c class:
#protocol YTManagerDelegate <NSObject>
#required
- (void)uploadProgressPercentage:(int)percentage;
#end
...
and a swift class connected to it:
class YTShare: UIViewController, YTManagerDelegate{
func uploadProgressPercentage(percentage:Int?){
println(percentage)
}
...
I receive the error: type YTShare does not conform to protocol YTShareDelegate, I have probably write incorrectly the swift function so the obj class don't find it. How I can write it correctly?
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.