Calling Swift from Objective C, closure to block? - ios

I started converting an Objective c project to Swift.
First thing I am converting is the network layer.
I'm trying to write my network layer in Swift in a way that it can be called from objective c.
The problem is in my swift code I'm passing closures to a method. It works in Swift, but doesn't seem like when generating header files it generates method definition for any method that is using closures?
Is there a workaround for this, or any way where I could have a swift method that takes a closure/block?
Swift class
#objc public class UserNetworkManager: BaseNetworkManager {
// I can call this from objective c
public func fetchSomething() {
}
// I can't call this from objective c
public func fetchFriends(userId: String, completion: ([User]?, NSError?)->()) -> Request {
}
}
Generated Header
SWIFT_CLASS("_TtC12Company19UserNetworkManager")
#interface UserNetworkManager : BaseNetworkManager
- (void)fetchSomething;
#end

There shouldn't be any issue converting your closure to a block as long as every type involved can be translated to Objective-C. In this case, it's likely that you haven't tagged your User and Request classes as #objc, which would prevent this method from being generated.

To instantiate an Objective-C class in Swift, you call one of its initializers using Swift initializer syntax.
Objective-C initializers begin with init, or initWith: if the initializer takes one or more arguments. When an Objective-C initializer is imported by Swift, the init prefix becomes an init keyword to indicate that the method is a Swift initializer. If the initializer takes an argument, the With is removed and the rest of the selector is divided up into named parameters accordingly.

Related

Unable to access to Swift 4.2 class included in a framework into Objective C Project

I've got a framework built in both Objective C and Swift. I've upgraded it from Swift 3 to Swift 4.2, and now, after exporting it through Aggregate target and importing the generated framework inside my Objective C demo app, it doesn't show me any Swift class.
I've already checked if -swift.h is correctly builded, and I can see inside it all Swift classes. However, even if I import the umbrella header inside my demo app, I can't see them.
Thanks
By default Swift generates code that is only available to other Swift code, but if you need to interact with the Objective-C runtime – all of UIKit, for example – you need to tell Swift what to do.
That’s where the #objc attribute comes in: when you apply it to a class or method it instructs Swift to make those things available to Objective-C as well as Swift code. So, any time you want to call a method from a UIBarButtonItem or a Timer, you’ll need to mark that method using #objc so it’s exposed – both of those, and many others, are Objective-C code.
class MyController: UIViewController {
#objc func authenticateUser() {
}
To make this class accessible from Objective-C, we need to add the #objc keyword just before the class declaration. This tells the compiler to do some magic behind the scenes (namely, create an invisible header file)
#objc class SwiftViewController: UIViewController {
// ...
}
Reference - https://www.hackingwithswift.com/example-code/language/what-is-the-objc-attribute

Objective-C call Swift function

Swift function defined in MySwift.swift File:
func SomeSwift()
{
}
SomeSwift() is not defined in any Swift class, it is just a pure function.
After CMD + B to build the project, open Project-Swift.h, the SomeSwift() isn't show in there.
Does the function in Swift have to be defined in some Swift class? and with #objc marked?
like the following:
#objc class SomeSwift: NSObject {
func SomeSwift()
{
}
}
Referring to Apple Documentation about Using Swift from Objective-C:
A Swift class must be a descendant of an Objective-C class to be
accessible and usable in Objective-C
Means that your class should be #objc class SomeSwift: NSObject (You're right!), but you CANNOT access the whole thing in Swift file:
When you create a Swift class that descends from an Objective-C class,
the class and its members—properties, methods, subscripts, and
initializers—that are compatible with Objective-C are automatically
available from Objective-C. This excludes Swift-only features, such as
those listed here:
Generics
Tuples
Enumerations defined in Swift without Int raw value type
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
Reference.
So, you cannot use the SomeSwift top-level function.
Even if you tried to add #objc before its declaration, the compiler will tell that:
#objc can only used when with memebers of classes, #objc protocols,
and concrete extensions of classes.
with a suggestion to remove #objc.

Initializing swift class in objective c project causes infinite loop

I'm trying to add a color picker in my add and I use this https://github.com/gizmosachin/ColorSlider library which is only written in swift and I use objective-c. I have followed this guide How to call Objective-C code from Swift on how to add swift libraries in objective-c projects. I'm 99% sure that I have properly configured xcode because I can import the swift library and run my app without an error, it's only when I try to instantiate the swift class that the app crashes and I see that the init method for the swift class is called infinitely. The source code for the library is one file and listed for reference just in case (https://github.com/gizmosachin/ColorSlider/blob/master/Source/ColorSlider.swift)
Here is one of the init methods (the other inits are overrides)
// MARK: Initializers
convenience init() {
println("hi there swift")
self.init()
backgroundColor = UIColor.clearColor()
}
in my log I see "hi there swift" print out many times. This is how I initiate the swift class
ColorSlider *colorSlider = [[ColorSlider alloc] init];
I know that the function containing the line of code above is only being called once because I used NSLog(#"output") to see how many times this shows up and the output looks like this
output
hi there swift
hi there swift
hi there swift
hi there swift
hi there swift
etc...to infinity or until app crashes
Am I instantiating the swift class correctly? I'm not sure why the swift class's init method is called infinitely
----UPDATE-----
It looks as if the init methods below also use super.init?
As in Objective-C a class can have convenience (secondary) initializers and designated (primary) initializers.
The path of code execution should be:
A convenience initializer should call a designated initializer with self.designatedInit().
A designated initializer should call a super's designated initializer with super.designatedInit().
In your code, init() is a convenience initializer (convenience init()). calling self.init() would lead to an infinite loop, because this is the actually running function itself as Dan said.
If you change it to super.init() a convenience initializer is calling a super's initializer, what is illegal because of the above rule #1.
What to do?
Check, whether init() is really a convenience initializer.
If so, call self.designatedInit() instead of self.init().
If not so, change the classification of init() and call super.init() (or whatever is the designated initializer of the super class.
Remove self.init. The method is calling itself.

Do I need to declare a method prior to the first use of the method in same class?

I am new in Objective C, and working in C/C++ till now.
In C/C++, if function do not know prototype of function, it will not call that function, even if it is in same file. So we either use header file, or write prototype before using it. Like,
void proto(void);
void somefun()
{
proto(); //call the function
}
But in Objective C, I have function in same file, but I can call it without giving its prototype. Following is code which is compiling correctly.
//calling before actually declaring/defining, but works fine.
[self processResponse:responseObject];
-(void)processResponse:(id)responseObject
{
}
Can Objective C calls functions without knowing prototype if it is in same class? What should I prefer?
Please note that processResponse is internal function. I do not want it to expose it to any other class.
Can Objective C calls functions without knowing prototype if it is in same class?
Yes it will try to call it.
What should I prefer?
It is better to declare the function in private extention part of the implementation file(.m) since you dont want to expose that function to other class.
Advandtages:
1.Other Peer can understand the method only as internal
2.Other than that class, no one can access it.
in Implementation file(.m)
#interface MyClass ()
-(void)processResponse:(id)responseObject;
#end
#implementation MyClass
#end
You are comparing functions with methods. Functions still have same rules as in C. As for objective C methods there are no prototypes. You may declare the method in header or as a class extension but those make them public. As for protected methods you do not need anything, just create the method and call it from anywhere inside the class.
It used to be that you had to put these privet methods on top of the class to use them (method B could call method A only if method A was written above the method B) but that was a long time ago.
Just like in C in Objective-C you have to declare a function before using it. What you are doing in your example is not calling function before declaring it but sending a message (or invoking a method if we want to use a more OOP terminology) to an object. Which is a different thing.
Anyway for all the versions of the LLVM compiler included in Xcode starting from version 4.3 the order of methods declaration doesn't matter anymore since if the compiler encounter a not yet declared method it will look in the rest of the #implementation block to see if it has been declared later.

can C function call objective-C class method?

id object_pointer;
(obj init method)...
object_pointer = self;
void some-c-function( void )
{
// Calling a class method from this C function:
[Some_Obj_C_Class class_method];
// or to calling an object method:
[object_pointer object_method];
}
I have to write my highest level code in C functions so that part can be eventually ported to an embedded system. I'm using iPads to simulate the hardware that's not available yet.
A C function can most certainly call an Objective-C method. In fact, a C function can even be an Objective-C method. Talking about how that works gets into the Objective-C runtime, a slightly related topic. An Objective-C method with no arguments can be thought of like a C function with exactly two arguments: self and _cmd. At compile time, Objective-C method calls are translated into calls to one of the objc_msgSend functions, which takes a selector and an object, in addition to any method arguments.
One thing that may be confusing is that because self is a sort of hidden argument in most methods, it will be inaccessible from a standard C function, even if you have it defined inside the #implementation of your object. As long as you are using Objective-C variables that are accessible in the scope of your function, you can make Objective-C method calls.

Resources