Say if i have a method as follows;
- (void)carpentorLoad {
NSlog(#"HI... Hello");
}
Now, i need to call this method from another method, say - (int) CallingMethod
-(int) CallingMethod{
// Here, i need to call carpentorLoad Method
return 0;
}
How should i call carpentorLoad from CallingMethod do this?
Are these methods in the same class? If so you can just do:
- (int) CallingMethod {
[self carpentorLoad];
return 0;
}
If they are in different classes, then you'll need to pass a reference to the second class into your calling method, like:
- (int) CallingMethod: (Carpentor*)theCarpentor {
[theCarpentor carpentorLoad];
return 0;
}
Assuming they are the same object, you would call [self carpentorLoad].
If carpentorLoad is a member of another class, either call [<ClassName> carpentorLoad] or [<yourObject> carpentorLoad], depending on if it is a static or instance method, respectively.
In Objective-C, you don't call methods, you send messages. The Obj-C runtime matches your message to a method in the reciever's class or one of its ancestor classes, and then calls the method it finds.
Related
I am messing around with method swizzling and would like to call the original function after performing a method_exchangeImplementations. I have two projects I have setup for this.
The first project is the main project for the application. This project includes all of the logic for the application. Notice that originalMethodName is called when the view loads.
#implementation ViewController
- (void)originalMethodName
{
NSLog(#"REAL %s", __func__);
}
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"REAL %s", __func__);
[self originalMethodName];
}
#end
The second project includes only the code for swizzling. I have a method swizzle_originalMethodName which includes the code I want to inject into the main application with the originalMethodName function is called.
#implementation swizzle_ViewController
- (void)swizzle_originalMethodName
{
NSLog(#"FAKE %s", __func__);
}
__attribute__((constructor)) static void initializer(void)
{
NSLog(#"FAKE %s", __func__);
Class c1 = objc_getClass("ViewController");
Class c2 = [swizzle_ViewController class];
Method m1 = class_getInstanceMethod(c1, #selector(originalMethodName));
Method m2 = class_getInstanceMethod(c2, #selector(swizzle_originalMethodName));
method_exchangeImplementations(m1, m2);
}
#end
The swizzle is working just fine (as seen in the output below), but now I want to be able to call originalMethodName from the swizzle_originalMethodName
2016-08-17 14:18:51.765 testMacOS[7295:1297055] FAKE initializer
2016-08-17 14:18:51.822 testMacOS[7295:1297055] REAL -[ViewController viewDidLoad]
2016-08-17 14:18:51.822 testMacOS[7295:1297055] FAKE -[swizzle_ViewController swizzle_originalMethodName]
I have tried to use NSInvocation but am not having any luck. Any ideas what I am doing wrong?
Class c1 = objc_getClass("ViewController");
Method m1 = class_getInstanceMethod(c1, #selector(originalMethodName));
NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:method_getTypeEncoding( m1)];
NSInvocation *originalInvocation = [NSInvocation invocationWithMethodSignature:methodSignature];
[originalInvocation invoke];
If you are swizzling within a class hierarchy, e.g. you have a subclass which swizzles one of its ancestors methods with one of its own, then you simply have the swizzled-in method apparently call itself – that call will actually call the swizzled-out method as the methods have been swapped. In your case you would have:
- (void)swizzle_originalMethodName
{
NSLog(#"FAKE %s", __func__);
[self swizzle_originalMethodName]; // call original
}
This does not work in your case as you are cross-class swizzling, so self doesn't reference the class with the swizzled-out method. And you don't have an instance of the swizzling class you can call the swizzled-out method on...
Here is one easy way to fix this, what your swizzle-in method needs to be able to do is call the original implementation, and you can get that when you setup the swizzling.
In Objective-C a method is implemented by a function whose first two arguments are the object reference the method is being called on and the selector and the remaining arguments are those of the method. For example the NSString method:
- (NSRange)rangeOfString:(NSString *)aString
is implemented by a function something like:
NSRange rangeOfStringImp(NSString *self, SEL cmd, NSString *aString)
You can obtain a function pointer to this implementation function using method_getImplementation.
To your code, first in your swizzle_ViewController declare a type for the implementation function of the method you are swizzling, and a global to store the function pointer:
typedef void (*OriginalImpType)(id self, SEL selector);
static OriginalImpType originalImp;
Now in your initializer method you need to save the method implementation, you can do this by adding the line shown:
Method m1 = class_getInstanceMethod(c1, #selector(originalMethodName));
originalImp = (OriginalImpType)method_getImplementation(m1); // save the IMP of originalMethodName
Finally have your swizzled-in method call the saved implementation:
- (void)swizzle_originalMethodName
{
NSLog(#"FAKE %s", __func__);
originalImp(self, #selector(originalMethodName)); // call the original IMP with the correct self & selector
}
Optional: The above works correctly, however it does a little more than is required – the method implementations are both exchanged and one is stored in a global variable, all you really need to do is save the original implementation of m1 and then set its implementation to that of m2. You can address this by replacing the call to method_exchangeImplementations with:
method_setImplementation(m1, method_getImplementation(m2));
It is a little more typing, but somewhat clearer as to what actually needs to be done.
HTH
There is a slightly easier option to call the original implementation that doesn't require you to store the method implementation directly. When you exchange implementations of the methods, the original implementation will be stored in the swizzler class. You can fetch the swizzled out implementation using the class_getMethodImplementation function. Here is a playground sample:
import Cocoa
let fooSelector = Selector("fooWithArg:")
let swizzledFooSelector = Selector("swizzled_fooWithArg:")
class A: NSObject {
#objc dynamic func foo(arg: String) {
print("Foo \(arg) in A")
}
}
class B: NSObject {
private typealias FooFunc = #convention(c) (AnyObject, Selector, String) -> Void
#objc func swizzled_foo(arg: String) {
print("Swizzled_foo \(arg) in B")
unsafeBitCast(
class_getMethodImplementation(B.self, swizzledFooSelector),
to: FooFunc.self
)(self, fooSelector, arg)
}
}
method_exchangeImplementations(
class_getInstanceMethod(A.self, fooSelector)!,
class_getInstanceMethod(B.self, swizzledFooSelector)!
)
A().foo(arg: "bar")
Mehul has defined this method.
+(BOOL)isCameraDeviceAvailable
{
BOOL isCameraAvailable=NO;
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
if([UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront] || [UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear])
isCameraAvailable = YES;
}
return isCameraAvailable;
}
But I cannot declare it properly and am getting the error
Instance method '-isCameraDeviceAvailable' not found (return type defaults to 'id')
when I declare it as follows.
+ (BOOL)isCameraDeviceAvailable;
and then use it this way
if([self isCameraDeviceAvailable]){
}
I suppose I need to declare it in a different place or in a different way. Can you tell me how to do this?
[self isCameraDeviceAvailable]
is an instance method call, not a class method call.
You have to use it like this:
[MyClass isCameraDeviceAvailable]
+(BOOL)isCameraDeviceAvailable
The + at the beginning of the line makes this a class method, which means that you can only send isCameraDeviceAvailable to the class. If you want to use the method with an instance of that class, you'll need to declare it that way by using a - instead of +:
-(BOOL)isCameraDeviceAvailable
Or, as Kashiv explains, you can use the method as you have it by sending isCameraDeviceAvailable to the class instead. See Objective-C Classes Are also Objects for more information.
I am aware of NSStringFromClass.
My question relates to the situation where the same method is implemented in multiple classes in an inheritance tree, and you want to debugging information as to which class it is executing from.
Example:
Let us have three classes: A-->B-->C , inheriting as displayed by the arrows.
If each of them has a method foo(), defined:
-(void) foo
{
// Do some work particular to the class it is in.
.....
//Each method ends with the debugging statement:
NSLog("In foo of class:%$",NSClassFromString([self class]));
}
The problem occurs when foo of Class B, calls [super foo]. When [super foo] (i.e. Class A) reaches the NSLog statement, [self class] returns class B, and not A.
Likewise if C called [super foo], the log statement in super would log class C.
What I want to do, is output the class whose method implementation is being executed - so if class B calls [super foo], then the log statement in [A foo] outputs Class A.
The simple way is to replace NSClassFromString with a hardcoded string representing the class name, but I was wondering if there is a better way to do this ?
You can use __PRETTY_FUNCTION__ to include both the class and the method name:
NSLog(#"Greetings from %s", __PRETTY_FUNCTION__);
I don't believe that there is a compiler-time macro for just the class name.
There might not be a macro for class, but there is __FILE__ and __LINE__ macros in the C language. They expand to the current file and line number. You can use them in NSLog. I use __PRETTY_FUNCTION__ when I remember it, but I remember __FILE__ and __LINE__ more.
Example:
NSLog( #"%s %d", __FILE__, __LINE__ );
Remember that __FILE__ isn’t an Objective-C string.
The problem occurs when foo of Class B, calls [super foo]. When [super
foo] (i.e. Class A) reaches the NSLog statement, [self class] returns
class B, and not A.
Sure. That's because self points to an object, and that object's class doesn't change just because you call a method of the superclass.
The simple way is to replace NSClassFromString with a hardcoded string
representing the class name, but I was wondering if there is a better
way to do this?
As others have pointed out, you can use a macro like __PRETTY_FUNCTION__, but I think the simple and obvious approach is the best. You know the name of the class when you're writing the code, so you can write:
NSLog("In foo of class: %#", #"ClassA");
Each of your classes has its own implementation of your method, so each one can print its own class name in the message. Something like __PRETTY_FUNCTION__ is useful when you're writing a debug macro that you're going to use in multiple functions. That's not the case here. Using the obvious approach makes it that much easier to see what's going on, and that's important during debugging (which I assume is what you're trying to do here).
i think you would have to walk up the class hierarchy using class_getSuperclass and class_getInstanceMethod, comparing differences in the methods. do that to determine the objc class, then use class_getName or NSStringFromClass to get its name.
This would look something like:
NSString* MONClassNameWhichImplementsMethod(id Self, SEL cmd);
and
- (void)method
{
NSLog(#"%# - %#",
MONGetClassWhichImplementsMethod(self, _cmd),
NSStringFromSelector(_cmd)
);
}
and
// NOT COMPILED -- FOR ILLUSTRATION ONLY
Class MONClassWhichImplementsMethod(Class cls, SEL cmd) {
assert(cls && cmd && "srsly?");
Class super = class_getSuperclass(cls);
Method m1 = class_getInstanceMethod(cls, cmd);
assert(m1 && "srsly?");
Method m2 = class_getInstanceMethod(super, cmd);
if (0 == m2) {
return cls;
}
else if (m1 != m2) {
return cls;
}
else {
return MONClassWhichImplementsMethod(super, cmd);
}
}
NSString* MONClassNameWhichImplementsMethod(id Self, SEL cmd) {
return NSStringFromClass(MONClassNameWhichImplementsMethod(Self.class, cmd));
}
if it blows up from deep recursion, you've another problem.
How come whenever I have to use awakeFromNib protocol I have to put it in this format?
-(void)awakeFromNib
What is the need for -(void)?
The -(void) is used in the declaration of the method. Presumably, you are defining it for someone else to call, rather than calling it yourself.
The - sign indicates that the method is an instance method, as opposed to a class method. It requires an object to call it, and instance variables of the object are available to it inside its definition.
The (void) indicates the return type. This method doesn't return anything, so its result can't be assigned to anything.
think of it this way
say you have a Class you created that is called "Math"
and this class has a method called "calculate". It's type as
-(int)calculate {
2+2;
return 2+2;
}
When you alloc the class and initialize the object and perform the "calculate method on that object, it's going to do the calculation 2+2 and it will return the result, 4.
If you tried
-(void)calculate {
2+2;
}
it wouldn't do anything, it would just have that 2+2 information stored in the method but the calculation would never occur.
Because the method does not return anything, and giving a void return type is how you declare that in C and Objective-C.
(void) marks the return type - in this case, void means it's returning nothing.
If it was instead -(int)awakeFromNib, you'd be expected to return an integer.
The meaning of the return value (if any) should be explained in the documentation.
I have a method in an objective-C class. It has 2 callback functions written in C. The class pointer i.e. self is passed to these functions as void *. In the C functions I create a pointer of type class and assign the void * parameter.
The first callback function executes successfully. But the void * pointer becomes nil in the 2nd callback function. Note that I haven't tweaked pointer in the first callback but still I get nil in 2nd callback.
Any ideas what might be going wrong?
For example:
kr = IOServiceAddMatchingNotification(gNotifyPort, kIOFirstMatchNotification,
matchingDict, RawDeviceAdded, NULL,
&gRawAddedIter);
RawDeviceAdded(NULL, gRawAddedIter, self);
This works fine. But below function receives self as nil.
kr = IOServiceAddMatchingNotification(gNotifyPort, kIOFirstMatchNotification,
matchingDict, BulkTestDeviceAdded, NULL,
&gBulkTestAddedIter);
BulkTestDeviceAdded(NULL, gBulkTestAddedIter, self);
Are your problems specifically with the IOKit callback routines? The problem with the specific example you gave is that the IOServiceMatchingCallback takes only 2 parameters, not 3. You need your RawDeviceAdded() and BulkTestDeviceAdded() callback functions to match the IOServiceMatchingCallback prototype and to accept self as the first parameter (refCon), not the 3rd. Also, you need to pass in self as the second-to-last parameter of IOServiceAddMatchingNotification() to get it passed back to you by the callback.
A common method for handling C callbacks in Objective-C code is just to have a static function that forwards the callback to your instance. So, your example callback code would look like this:
static RawDeviceAdded(void* refcon, io_iterator_t iterator)
{
[(MyClass*)refcon rawDeviceAdded:iterator];
}
#implementation MyClass
- (void)setupCallbacks
{
// ... all preceding setup snipped
kr = IOServiceAddMatchingNotification(gNotifyPort,kIOFirstMatchNotification, matchingDict,RawDeviceAdded,(void*)self,&gRawAddedIter );
// call the callback method once to 'arm' the iterator
[self rawDeviceAdded:gRawAddedIterator];
}
- (void)rawDeviceAdded:(io_iterator_t)iterator
{
// take care of the iterator here, making sure to complete iteration to re-arm it
}
#end
Generally, callbacks in Objective-C are handled by passing a delegate object and a selector to perform on that delegate. For example, this method will call a method on its delegate after logging a message, passing both itself and the message that was logged.
- (void)logMessage:(NSString *)message
delegate:(id)delegate
didLogSelector:(SEL)didLogSelector
{
NSLog(#"%#", message);
if (delegate && didLogSelector && [delegate respondsToSelector:didLogSelector]) {
(void) [delegate performSelector:didLogSelector
withObject:self
withObject:message];
}
}
You might call it in code like this:
- (void)sayHello
{
[logger logMessage:#"Hello, world"
delegate:self
didLogSelector:#selector(messageLogger:didLogMessage:)];
}
- (void)messageLogger:(id)logger
didLogMessage:(NSString *)message
{
NSLog(#"Message logger %# logged message '%#'", logger, message);
}
You can also use objc_msgSend() directly instead, though you need to understand the Objective-C runtime enough to choose which variant to use and how to construct the prototype and function pointer through which to call it. (It's the mechanism by which message sends are actually implemented in Objective-C — what the compiler normally generates calls to in order to represent [] expressions.)
This is what Objective-C's selector is for:
http://developer.apple.com/iphone/library/documentation/Cocoa/Reference/NSInvocationOperation_Class
The API isn't very intuitive, but its fine once you understand it
You might need to do some refactoring as well, now there might be a better way, but when I had this problem my solution was to refactor and use InvoationOperation.