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.
Related
I have the following snippet
let classByName = objc_lookUpClass("UIScreen")
let mainScreen = (classByName as? NSObjectProtocol)?.perform(Selector("mainScreen"))?.takeRetainedValue()
print(mainScreen) // Optional(<UIScreen: ....
print(mainScreen?.perform(Selector("brightness")).takeUnretainedValue()) // Optional(<UIDevice:...
As you can see the second method returns a reference to the current UIDevice instead of the CGFloat corresponding to a screen brightness...
Any idea on what's going on here?
You run into a corner case due to using dispatch methods that are not recommended in Swift.
Please note that everything you read below is related to the Objective-C message passing (aka method calling). When interoperating with Objective-C classes, the Swift compiler generates (more or less) the same caller code as the Objective-C compiler, so anything that applies to Objc, also applies to Swift code calling ObjC.
First of all, performSelector should not be used on methods that return float, since behind the scenes performSelector calls objc_msgSend, however for methods that return a float, the internal result of objc_msgSend is read from the wrong location.
A little bit of background of objc_msgSend - this function is at the core of the Objective-C dynamic dispatch, basically any method call on an Objective-C object results in objc_msgSend being called. I won't get into too many details here, there are many online materials about objc_msgSend, just want to summarize that the function is a very versatile one, and can be casted to match any method signature.
So, let's take the brightness example. What actually happens behind the scenes when using performSelector (the Objective-C method named in Swift perform(_:))? This is roughly how performSelector is implemented:
- (void)performSelector:(SEL)selector) {
return objc_msgSend(self, selector);
}
Basically the method simply forwards the value resulted by calling objc_msgSend.
Now the things get interesting. Because floats and ints use different return locations, the compiler will need to generate different reading location depending on its knowledge about the type of data returned by objc_msgSend.
And if there's a misunderstanding between what the compiler thinks objcSend will return, and what actually the function returns, then bad things might happen. But in your case there's a "fortunate" coincidence due to which your program doesn't crashes.
Basically your perform(Selector("brightness") call results in a objc_msgSend(mainScreen, Selector("brightness")) call that assumes that objc_msgSend will return an object. But in turn the called code - the brightness getter - returns a float.
So why isn't the app crashing when the Swift code tries to print the result (actually it should crash on takeUnretainedValue)?
It's because floats and ints (and object pointers are in the same category as int) have different return locations. And the performSelector reads from the return location for ints, as it expects an object pointer. Fortunately, at that point in time, the last method called is likely a method that returns an UIDevice instance. I assume that internally UIScreen.brightness asks the device object for this information.
Something like this happens:
1. Swift code calls mainScreen?.perform(Selector("brightness")
2. This results in Objective-C call [mainScreen performSelector:selector]
3. objc_msgSend(mainScreen, selector) is called
3. The implementation of UIScreen.brightness is executed
4. UIScreen.brightness calls UIDevice.current (or some other factory method)
5. UIDevice.current stores the `UIDevice` instance in the int return location
6. UIScreen.brightness calls `device.someMemberThatReturnsTheBrightness`
7. device.someMemberThatReturnsTheBrightness stores the brightness into
the float return location
8. UIScreen.brightness exits, its results is already at the proper location
9. performSelector exits
10. The Swift code expecting an object pointer due to the signature of
performSelector reads the value from the int location, which holds the
value stored at step #5
Basically, it's all about calling conventions, and about how your "innocent" code gets translated into assembly instructions. This is why the fully dynamic dispatch is not recommended, because the compiler doesn't have all the details to construct a reliable set of assembly instructions.
So this question has an obvious answer: "because the compiler won't let you" but I'm hoping someone can explain to me why this part of Swift works the way it does.
I ran into this question because I was building a view controller that needed to satisfy a protocol (UIImagePickerControllerDelegate). The protocol requires a callback function to call after a user selected an image. I wanted to be able to change the callback behavior at runtime.
Coming from a Python background, I figured that should be easy: just define the callback method on my class to satisfy the protocol and then redefine it later by just reassigning to it. That works perfectly fine in Python:
class Foo(object):
def bar(self):
print "bar"
foo = Foo()
foo.bar() # output "bar"
def baz():
print "baz"
foo.bar = baz
foo.bar() # output "baz"
But it doesn't work in Swift (even though I can do very nearly the same thing by declaring a variable to hold a closure):
import UIKit
class Foo {
func bar() -> String {
return "bar"
}
var baz: ()-> String = {
return "baz"
}
}
let foo = Foo()
foo.bar() // output: bar
foo.baz() // output: baz
let gee = {
return "gee"
}
foo.baz = gee
foo.baz() // output: gee
foo.bar = gee // error: cannot assign to bar in foo
So the question...why does Swift work this way? It's clearly not because it's impossible to alter function routing at runtime (otherwise the closure assignment wouldn't work). My best guess is that it's analogous to the let/var distinction for variables and that using "func" is implicitly telling the compiler that a function should be immutable. And I grant that it may be better to make instance methods immutable by default. But it is annoying when we need to comply with rigid protocols from UIKit. At least it would be nice if I could use a variable to satisfy a function requirement in a protocol.
(For the curious: I worked around this issue by declaring an instance variable to hold a closure that can be reassigned. I then declared the required protocol function and made it do nothing but call the closure. Which might(?) cause a retain cycle, but works.)
The code the compiler is allowed to emit is fundamentally different.
Making a simple test, compiling with -Onone for readability, and disassembling with Hopper, you can see what's going on (comments added manually):
In the case of an "instance method"/function, they can be called after being looked up in the vtable — in this example, *(*rax + 0x48) and *(*rax + 0x70) are pointers to the functions, and they're passed rax (the object itself) as a parameter (this becomes self).
However in the case of a closure variable, *(*rax + 0x50) is a pointer to the getter for bar. The getter is called first, and returns the closure which is then called — (rax)(rdx).
So these are simply different things. If you have a modifiable property that stores a closure, then certainly you need to call the getter before you can call the closure (since the value could have changed by being set elsewhere). But simple function dispatch doesn't require the extra level of indirection.
Im not certain how functions and closures work behind the scenes in swift, but i would think a function in swift is basically like a function in c, its defined at runtime and thats it. its compiled and lives at a certain address in memory and anything referencing that function has to look at that memory address, and that cant change at runtime.
A closure i would see as like a function pointer + normal function combination in c. so its probably a limitation of the way they implemented the function in swift. in python maybe behind the scenes everything is implemented like a function pointer + normal function.
as to why swift didnt implement it like python, i think only someone who works at Apple could tell you that, but maybe there is some overhead with using everything like a closure instead of just plain functions, so they make you only use closures when needed and the rest should be functions.
also having functions immutable could be the reason why protocols work behind the scenes, maybe allowing you to change the function at run time would break the protocol system.
Im not sure if anyone here is really fit to answer this (besides an apple employee lurking here maybe), but this is my best guess
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.
I want to get current method name to use in a format message similar to this one
[NSExeception raise:NSInternalInconsistencyException format:#"You must override %# in a subclass", NSStringFromSelector(_cmd)]
Also, I want to use _cmd to set associated object. I appreciate any idea.
NSStringFromSelector(_cmd); // Objective-C
print(#function) // Swift 4, 5
There is no Swift equivalent of _cmd. There is little reason to use it in Swift.
Consider _cmd in Objective-C. When is it useful? Most of the time, the value of _cmd would be the same as the name of the method that the code is in, so it is already known at compile time, and there is no need for a runtime value. Here are some possible cases when _cmd is useful in Objective-C:
In a macro. The macro is expanded in the code, so if _cmd appears in the macro, then it is inserted into the source where it is used, and so the method name can be used inside the macro. However, such macros do not exist in Swift. Plus macros are compile-time, so a compile-time mechanism like __FUNCTION__ would work similarly.
You can define a C function that takes self and _cmd, and use it (the same function) as the implementation of multiple methods, by adding it using class_addMethod and class_replaceMethod, and the _cmd inside the function will help distinguish between the different method calls. However, class_addMethod and class_replaceMethod are not available in Swift.
Method swizzling is also a process that messes with the implementation of a method. Since in swizzling you swap the implementations of two methods, _cmd will help reveal the actual method name used in the call, which may not match the method that the code is in in the source code, since implementations are swapped. I guess method swizzling may still be possible in Swift, since method_exchangeImplementations is still available in Swift. But in method swizzling, the method you swap in is tailored for the method it is swapping with, so if it is called, there is no ambiguity which method name is being called.
In the case where you manually get the IMP (implementing function) of a method, and manually call it with a different selector. In this case, the inside of the function can see the different selector in _cmd. However, you don't have to worry about this in Swift because the methods that get the IMP are unavailable.
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.