How to call my method in cocoa, self doesn't work - objective-c

Working on a program that will record some things from the webcam when a user presses physical buttons connected to the mac via phidgets. Have call methods on other places in my app simply doing [self method: input], but on one place it doesn't work. What could be wrong?
This is the method i want to run if i get inputchange in my program.
Also i do -(void)reportButton2:(NSInteger)inputVal:(NSInteger)inputInd; in my .h file.
-(void)reportButton2:(NSInteger)inputVal:(NSInteger)inputInd {
//NSLog(#"phidget för port = %%d med signal %%d", ind, val);
if(inputVal == 1)
{
NSError* error;
NSFileManager* deleteMgr = [NSFileManager defaultManager];
NSString* path = #"/Users/Shared/tempFile.mov";
[deleteMgr removeItemAtPath:path error:&error];
[mCaptureMovieFileOutput recordToOutputFileURL:[NSURL fileURLWithPath:#"/Users/Shared/tempFile.mov"]];
}
else if(inputVal == 0)
{
[mCaptureMovieFileOutput recordToOutputFileURL:nil];
}
}
The code below give me result if imput from the buttons change. Here i just can't seem to call reportbutton2.
If i try to use [self reportButton2..] in gives me "Use of undeclared identifier 'self'"
int gotInputChange(CPhidgetInterfaceKitHandle phid, void *context, int ind, int val) {
what to do here?
return 0;
}

The problem is that gotInputChange is a C function not a Objective C method and so has no udea what self is as it does not belong to a class.
for [self reportButton2... = to work it needs to be a method in your class

I usually put something like this at the top of callbacks like gotInputChange:
MyObject *self = (id)context;
Then I can use self throughout the function as if it were a method.
The other thing being in a function makes harder is asserting conditions. The regular assertion macros, such as NSAssert and NSParameterAssert, require both of the implicit arguments to every method (self is one of them) to exist. In a C function, you must use NSCAssert, NSCParameterAssert, etc. instead.

You can also use your delegate.
SomeNameAppDelegate *delegate = (SomeNameAppDelegate *)[[NSApplication sharedApplication] delegate];
[delegate yourMethodName];
It works like in example if your target method in AppDelegate class. But when you have an access to delegate, you can create a pointers to necessary classes and use them over delegate.

Quickest but not soo nice way is to make your Class a singleton and access it from the gotInputChange function.

Okay thanks! Din't have any clue that it was C would never have solved it by myself. Did some googeling and this one did the trick for me.
[(id)context performSelectorOnMainThread:#selector(reportButton2:)withObject:[NSArray arrayWithObjects:[NSNumber numberWithInt:ind], [NSNumber numberWithInt:val], nil] waitUntilDone:NO];

Related

Objective C - caller Object of a method [duplicate]

Example: When my method -fooBar gets called, I want it to log in the console which other method of which other class called it.
Right now, I only know how to log the method name of fooBar itself and it's class, with this:
_cmd
[self class]
Is this possible to figure out?
In fully optimized code, there is no 100% surefire way to determine the caller to a certain method. The compiler may employ a tail call optimization whereas the compiler effectively re-uses the caller's stack frame for the callee.
To see an example of this, set a breakpoint on any given method using gdb and look at the backtrace. Note that you don't see objc_msgSend() before every method call. That is because objc_msgSend() does a tail call to each method's implementation.
While you could compile your application non-optimized, you would need non-optimized versions of all of the system libraries to avoid just this one problem.
And this is just but one problem; in effect, you are asking "how do I re-invent CrashTracer or gdb?". A very hard problem upon which careers are made. Unless you want "debugging tools" to be your career, I would recommend against going down this road.
What question are you really trying to answer?
How about this:
NSString *sourceString = [[NSThread callStackSymbols] objectAtIndex:1];
NSCharacterSet *separatorSet = [NSCharacterSet characterSetWithCharactersInString:#" -[]+?.,"];
NSMutableArray *array = [NSMutableArray arrayWithArray:[sourceString componentsSeparatedByCharactersInSet:separatorSet]];
[array removeObject:#""];
NSLog(#"Class caller = %#", [array objectAtIndex:3]);
NSLog(#"Method caller = %#", [array objectAtIndex:4]);
Credits to the original author, intropedro.
It's not possible in the general case without actually walking the stack. There's not even a guarantee that another object send the message that called the method. For example, it could be called from a block in a signal handler.
NSLog(#"Show stack trace: %#", [NSThread callStackSymbols]);
See backtrace(3).
User the below method
Pass index for which you want to display method and pass -1 if you want to display full stack of method
+(void) methodAtIndex:(int)index{
void* callstack[128];
int frames = backtrace(callstack, 128);
char** strs = backtrace_symbols(callstack, frames);
if (index == -1) {
for (int i = 0; i < frames; ++i) {
printf("%s\n", strs[i]);
}
}
else {
if (index < frames) {
printf("%s\n", strs[index]);
}
}
free(strs);
}
This information can be obtained using DTrace.
Make a macro that adds the __FUNCTION__ to the function name to the function call. This macro will then call your function with an extra parameter of a char* to the target function.
I was trying to catch who, how and when changes window's size and did some handwork:
- (void)logWindowWidth:(NSString *)whoCalls {
NSLog(#"%#", whoCalls);
NSLog(#"self.window.size.width %f", self.window.size.width);
}
-(void)someMethod {
[self logWindowWidth:#"someMethod - before"];
...
[self logWindowWidth:#"someMethod - after"];
}
-(void)anotherMethod {
[self logWindowWidth:#"anotherMethod - before"];
...
[self logWindowWidth:#"anotherMethod - after"];
}

calling super from within a GCD dispatch_async block: is it safe?

I'm in a bit of a pickle. I know that calling [self methodName] from within a block will lead to a retain cycle.
However in this class due to multithreading I cannot allow execution of the method that the block is accessing from anywhere else other than the block, as it would potentially lead to serious problems.
Current code:
if (_getRunning==NO){
__weak SyncArrayMT *_weak_self = self;
_get_t = ^void (void){
_weak_self->_getRunning = YES;
NSArray *objects = [_weak_self get:getQuery
usingClassCtor:ctor
withAuthBlock:authBlock];
if (_weak_self.getBlockCb)
_weak_self.getBlockCb(objects);
_weak_self->_getRunning = NO;
};
}
Does exactly that, it calls [self getmethod]. While its ok for the dispatched block to run this method, I do not want anything outside this class calling this method.
So, would it be ok to override this inherited method as such:
- (NSArray *) get:(NSString *)getQuery usingClassCtor:(initBlock)initCb withAuthBlock:(authenticate)authBlock
{
NSLog(#"Direct call to get is not allowed - use the threaded method");
return nil;
}
And then change the block to this:
_get_t = ^void (void){
_weak_self->_getRunning = YES;
NSArray *objects = [super get:getQuery
usingClassCtor:ctor
withAuthBlock:authBlock];
if (_weak_self.getBlockCb)
_weak_self.getBlockCb(objects);
_weak_self->_getRunning = NO;
};
I have tried it and it works without doing a call to the [self getMethod], but will super be retained, properly released, etc? Yes I am using ARC. Would calling super within a block lead to any problem ? Is there a hack to get a __weak to super instead ?
Alternatively, how can I disallow direct calls to [self getMethod] (which is inherited) and only use it internally ?
I know that Objective-C doesn't exactly implement this, but I know there are tricks, such as declaring and implementing a method in the implementation file only.
EDIT#1:
I have tried with SEL & IMP and function pointers. Problem is that IMP and function pointers require as a parameter an instance, and this renders the hole point mute:
NSString * (*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[super methodForSelector:#selector(sendObjectsPassingTest:withAuthBlock:)];
NSString *reply = getFuncPtr(_weak_self,#selector(sendObjectsPassingTest:withAuthBlock:),predicate,authBlock);
This simply calls the inherited method. Trying to use it with super simply gives an error. At this point I will go ahead and simply use super within the block, and try and profile to see if it leads to any retain cycle.
EDIT#2:
Based on newacct's answer, this is what I ended up doing:
typedef NSArray * (* getFuncPtr)(id,SEL,id,id,id);
...
...
__weak SyncArrayMT *_weak_self = self;
_getMethod = (NSArray * (*)(id,SEL,id,id,id))[[[self class] superclass] instanceMethodForSelector:#selector(get:usingClassCtor:withAuthBlock:)];
_get_t = ^void (void){
NSArray *objects = _weak_self->_getMethod(_weak_self,#selector(get:usingClassCtor:withAuthBlock:),getQuery,ctor,authBlock);
}
I am hoping this should avoid any retain cycles, although I haven't actually profiled it yet.
I know that calling [self methodName] from within a block will lead to
a retain cycle.
That is not true in general. The block will retain self, yes. But there will only be a "retain cycle" if self somehow retains the block. In this case, it does.
but will super be retained
Yes, self will be retained (super is a call on self with a different method lookup pathway).
I have tried with SEL & IMP and function pointers. Problem is that IMP
and function pointers require as a parameter an instance, and this
renders the hole point mute:
NSString * (*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[super methodForSelector:#selector(sendObjectsPassingTest:withAuthBlock:)];
NSString *reply = getFuncPtr(_weak_self,#selector(sendObjectsPassingTest:withAuthBlock:),predicate,authBlock);
This simply calls the inherited method. Trying to use it with super simply gives an error. At this point I will go ahead and simply use super within the block, and try and profile to see if it leads to any retain cycle.
There are many wrong points here. First, as said above, super is a call on self (there is no such thing as a super object), so it would be sufficient to get the IMP for the method in the superclass, and call it on self.
BUT, [super methodForSelector:... does not get the method in the superclass. It actually gets the method in this class. The super in [super methodForSelector:... affects which methodForSelector: method is called. However, no class ever overrides methodForSelector:, so there is actually no difference between [super methodForSelector:... and [self methodForSelector:.... As said above, super calls the method on self, so it still finds the method based on the class of the current object.
You can get the right IMP by using the class method +instanceMethodForSelector::
NSString *(*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[[[self class] superclass] instanceMethodForSelector:#selector(sendObjectsPassingTest:withAuthBlock:)];
However, using the above will not work correctly if the current object is an instance of a subclass, because then [self class] will be the subclass. So to make sure it does what we want, we need to hard-code the name of our current class, or the superclass:
NSString *(*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[[SyncArrayMT superclass] instanceMethodForSelector:#selector(sendObjectsPassingTest:withAuthBlock:)];
NSString *reply = getFuncPtr(_weak_self,#selector(sendObjectsPassingTest:withAuthBlock:),predicate,authBlock);
It is also possible to do it using objc_msgSendSuper directly, but that function is not really that easy to use either. So I think you should stick with the IMP approach above.

How to add a category to a "hidden" class

Is there a way to add a category to a class whose header file you can't access?
For testing purposes, I want to add a category to UITableViewCellDeleteConfirmationControl, but the class is (as far as I can tell) part of a private framework.
How can I do that?
Elaboration (per mihirios's request):
I am trying to extend the Frank testing framework to simulate tapping the confirmation button (the big red "Delete" button) that appears when you try to delete a UITableViewCell. Frank adds a tap method to UIControl. For some reason, Frank's usual way of tapping a control does not work for the UITableViewCellDeleteConfirmationControl class (which subclasses UIControl).
I've create a workaround. I added a category to UITableViewCell, with the following method.
- (BOOL)confirmDeletion {
if (![self showingDeleteConfirmation]) {
return NO;
}
UITableView *tableView = (UITableView *)[self superview];
id <UITableViewDataSource> dataSource = [tableView dataSource];
NSIndexPath *indexPath = [tableView indexPathForCell:self];
[dataSource tableView:tableView
commitEditingStyle:UITableViewCellEditingStyleDelete
forRowAtIndexPath:indexPath];
return YES;
}
This finds the table's data source and invokes its tableView:commitEditingStyle:forRowAtIndexPath: method, which (according to the documentation for UITableView) is what the system does when the user taps the confirmation button.
This works, but I would prefer to make UITableViewCellDeleteConfirmationControl appear to be a tappable button by adding a tap method to it, overriding Frank's default one. The tap method would find the cell that contains the confirmation button, then invoke [cell confirmDeletion].
When I try to declare a category for UITableViewCellDeleteConfirmationControl, the compiler complains that it "can't resolve interface 'UITableViewCellDeleteConfirmationControl'."
When I try to use the header file that someone generated using class-dump, the linker complains that it can't find the symbol _OBJC_CLASS_$_UITableViewCellDeleteConfirmationControl.
For testing purposes, you can always get the class object using NSClassFromString and then use the class_replaceMethod runtime method to do whatever you need. See the Objective-C Runtime Reference for details.
As far as i know you can not use a Category, but you could add the methods manually during runtime.
A Possible way to do this is, to create a new class, implement the methods you want to, and send this methods to UITableViewCellDeleteConfirmationControl using the appropriate objc-runtime functions. There are some things to take care of, like storing the original functions for later use in case of overloading, also in your 'category'-class you have to pay attention when you want to call super, as this will not work, you have to use objc-runtime function objc_msgSendSuper instead.
As Long as you don't need to call super this will do fine:
#import <objc/runtime.h>
#import <objc/message.h>
void implementInstanceMethods(Class src, Class dest) {
unsigned int count;
Method *methods = class_copyMethodList(src, &count);
for (int i = 0; i < count; ++i) {
IMP imp = method_getImplementation(methods[i]);
SEL selector = method_getName(methods[i]);
NSString *selectorName = NSStringFromSelector(selector);
const char *types = method_getTypeEncoding(methods[i]);
class_replaceMethod(dest, selector, imp, types);
}
free(methods);
}
a good point to call the method is in main.m, for example:
#autoreleasepool {
implementInstanceMethods([MyCategory class], NSClassFromString(#"UITableViewCellDeleteConfirmationControl"));
return UIApplicationMain(argc, argv, nil, NSStringFromClass([YourAppDelegate class]));
}
But i don't know why you not just move the confirmation handling in the controller-class.
As long as the compiler can (eventually) link to the class in question you can create a category for it. The more important question will be how to design the category since it seems you do not have access to the source for the original class.

Objective-C & KeyValueCoding: How to avoid an exception with valueForKeyPath:?

I've got an object of type id and would like to know if it contains a value for a given keyPath:
[myObject valueForKeyPath:myKeyPath];
Now, I wrap it into a #try{ } #catch{} block to avoid exceptions when the given keypath isn't found. Is there a nicer way to do this? Check if the given keypath exists without handling exceptions?
Thanks a lot,
Stefan
You could try this:
if ([myObject respondsToSelector:NSSelectorFromString(myKeyPath)])
{
}
However, that may not correspond to the getter you have, especially if it is a boolean value. If this doesn't work for you, let me know and I'll write you up something using reflection.
For NSManagedObjects, an easy solution is to look at the object's entity description and see if there's an attribute with that key name. If there is, you can also take it to the next step and see what type of an attribute the value is.
Here's a simple method that given any NSManagedObject and any NSString as a key, will always return an NSString:
- (NSString *)valueOfItem:(NSManagedObject *)item asStringForKey:(NSString *)key {
NSEntityDescription *entity = [item entity];
NSDictionary *attributesByName = [entity attributesByName];
NSAttributeDescription *attribute = attributesByName[key];
if (!attribute) {
return #"---No Such Attribute Key---";
}
else if ([attribute attributeType] == NSUndefinedAttributeType) {
return #"---Undefined Attribute Type---";
}
else if ([attribute attributeType] == NSStringAttributeType) {
// return NSStrings as they are
return [item valueForKey:key];
}
else if ([attribute attributeType] < NSDateAttributeType) {
// this will be all of the NSNumber types
// return them as strings
return [[item valueForKey:key] stringValue];
}
// add more "else if" cases as desired for other types
else {
return #"---Unacceptable Attribute Type---";
}
}
If the key is invalid or the value can't be made into a string, the method returns an NSString error message (change those blocks to do whatever you want for those cases).
All of the NSNumber attribute types are returned as their stringValue representations. To handle other attribute types (e.g.: dates), simply add additional "else if" blocks. (see NSAttributeDescription Class Reference for more information).
If the object is a custom class of yours, you could override valueForUndefinedKey: on your object, to define what is returned when a keypath doesn't exist.
It should be possible to graft this behavior onto arbitrary classes reasonably simply. I present with confidence, but without warranty, the following code which you should be able to use to add a non-exception-throwing implementation of valueForUndefinedKey: to any class, with one, centralized line of code per class at app startup time. If you wanted to save even more code, you could make all the classes you wanted to have this behavior inherit from a common subclass of NSManagedObject and then apply this to that common class and all your subclasses would inherit the behavior. More details after, but here's the code:
Header (NSObject+ValueForUndefinedKeyAdding.h):
#interface NSObject (ValueForUndefinedKeyAdding)
+ (void)addCustomValueForUndefinedKeyImplementation: (IMP)handler;
#end
Implementation (NSObject+ValueForUndefinedKeyAdding.m):
#import "NSObject+ValueForUndefinedKeyAdding.h"
#import <objc/runtime.h>
#import <objc/message.h>
#implementation NSObject (ValueForUndefinedKeyAdding)
+ (void)addCustomValueForUndefinedKeyImplementation: (IMP)handler
{
Class clazz = self;
if (clazz == nil)
return;
if (clazz == [NSObject class] || clazz == [NSManagedObject class])
{
NSLog(#"Don't try to do this to %#; Really.", NSStringFromClass(clazz));
return;
}
SEL vfuk = #selector(valueForUndefinedKey:);
#synchronized([NSObject class])
{
Method nsoMethod = class_getInstanceMethod([NSObject class], vfuk);
Method nsmoMethod = class_getInstanceMethod([NSManagedObject class], vfuk);
Method origMethod = class_getInstanceMethod(clazz, vfuk);
if (origMethod != nsoMethod && origMethod != nsmoMethod)
{
NSLog(#"%# already has a custom %# implementation. Replacing that would likely break stuff.",
NSStringFromClass(clazz), NSStringFromSelector(vfuk));
return;
}
if(!class_addMethod(clazz, vfuk, handler, method_getTypeEncoding(nsoMethod)))
{
NSLog(#"Could not add valueForUndefinedKey: method to class: %#", NSStringFromClass(clazz));
}
}
}
#end
Then, in your AppDelegate class (or really anywhere, but it probably makes sense to put it somewhere central, so you know where to find it when you want to add or remove classes from the list) put this code which adds this functionality to classes of your choosing at startup time:
#import "MyAppDelegate.h"
#import "NSObject+ValueForUndefinedKeyAdding.h"
#import "MyOtherClass1.h"
#import "MyOtherClass2.h"
#import "MyOtherClass3.h"
static id ExceptionlessVFUKIMP(id self, SEL cmd, NSString* inKey)
{
NSLog(#"Not throwing an exception for undefined key: %# on instance of %#", inKey, [self class]);
return nil;
}
#implementation MyAppDelegate
+ (void)initialize
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[MyOtherClass1 addCustomValueForUndefinedKeyImplementation: (IMP)ExceptionlessVFUKIMP];
[MyOtherClass2 addCustomValueForUndefinedKeyImplementation: (IMP)ExceptionlessVFUKIMP];
[MyOtherClass3 addCustomValueForUndefinedKeyImplementation: (IMP)ExceptionlessVFUKIMP];
});
}
// ... rest of app delegate class ...
#end
What I'm doing here is adding a custom implementation for valueForUndefinedKey: to the classes MyOtherClass1, 2 & 3. The example implementation I've provided just NSLogs and returns nil, but you can change the implementation to do whatever you want, by changing the code in ExceptionlessVFUKIMP. If you remove the NSLog, and just return nil, I suspect you'll get what you want, based on your question.
This code NEVER swizzles methods, it only adds one if it's not there. I've put in checks to prevent this from being used on classes that already have their own custom implementations of valueForUndefinedKey: because if someone put that method in their class, there's going to be an expectation that it will continue to get called. Also note that there may be AppKit code that EXPECTS the exceptions from the NSObject/NSManagedObject implementations to be thrown. (I don't know that for sure, but it's a possibility to consider.)
A few notes:
NSManagedObject provides a custom implementation for valueForUndefinedKey: Stepping through its assembly in the debugger, all it appears to do is throw roughly the same exception with a slightly different message. Based on that 5 minute debugger investigation, I feel like it ought to be safe to use this with NSManagedObject subclasses, but I'm not 100% sure -- there could be some behavior in there that I didn't catch. Beware.
Also, as it stands, if you use this approach, you don't have a good way to know if valueForKey: is returning nil because the keyPath is valid and the state happened to be nil, or if it's returning nil because the keyPath is invalid and the grafted-on handler returned nil. To do that, you'd need to do something different, and implementation specific. (Perhaps return [NSNull null] or some other sentinel value, or set some flag in thread-local storage that you could check, but at this point is it really all that much easier than #try/#catch?) Just something to be aware of.
This appears to work pretty well for me; Hope it's useful to you.
There's no easy way to solve this. Key Value Coding (KVC) isn't intended to be used that way.
One thing is for sure: using #try-#catch is really bad since you're very likely to leak memory etc. Exceptions in ObjC / iOS are not intended for normal program flow. They're also very expensive (both throwing and setting up the #try-#catch IIRC).
If you look at the Foundation/NSKeyValueCoding.h header, the comment / documentation for
- (id)valueForKey:(NSString *)key;
clearly states which methods need to be implemented for -valueForKey: to work. This may even use direct ivar access. You would have to check each one in the order described there. You need to take the key path, split it up based on . and check each part on each subsequent object. To access ivars, you need to use the ObjC runtime. Look at objc/runtime.h.
All of this is vary hacky, though. What you probably want is for your objects to implement some formal protocol and then check -conformsToProtocol: before calling.
Are your key paths random strings or are those strings under your control? What are you trying to achieve? Are you solving the wrong problem?
I don't believe this is possible in a safe way (i.e. without mucking with -valueForUndefinedKey: or something similar on other peoples' classes). I say that because on the Mac side of things, Cocoa Bindings—which can be set to substitute a default value for invalid key paths—simply catches the exceptions that result from bad key paths. If even Apple's engineers don't have a way to test if a key path is valid without trying it and catching the exception, I have to assume that such a way doesn't exist.

How to check object is kind of block or not

How can we identify any particular object is kind of block or not?
for example,
NSSet *set =[NSSet setWithObjects:
#"name1",
#"name2",
[^{ /* ..... some code */ } copy],
nil];
How can we find out which object from set is kind of block?
There is a safer way to determine if something is a block without actually using private api or constructing a class using the private string name:
- (BOOL)isBlock:(id)item {
id block = ^{};
Class blockClass = [block class];
while ([blockClass superclass] != [NSObject class]) {
blockClass = [blockClass superclass];
}
return [item isKindOfClass:blockClass];
}
Wrap your block in a class of your own:
BlockWrapper *blockWrapper = [BlockWrapper wrapperWithBlock:^{ … }];
Check for the type and extract the actual block:
if ([obj isKindOfClass:[BlockWrapper class]]) {
codeBlock = [(BlockWrapper*)obj block];
}
There is no supported way to do this. You must keep track of what objects are blocks, and what their type signatures are.
Do you have a practical use case for a set of mixed strings and blocks?
It's possible, but I wouldn't recommend doing this, because NSBlock is not a public class and its name might change in the future:
if ([obj isKindOfClass:NSClassFromString(#"NSBlock")]) {
NSLog(#"It's a block!");
}
If you only have strings and blocks, just check ![thing isKindOfClass:[NSString class]]. i.e. invert your test.
Likewise, if you have strings, numbers and blocks, check that thing is not a string or a number, and in that case it must (by deduction) be a block. Either that, or your program is incorrect and will crash.
I suppose that ![thing isKindOfClass:[NSObject class]], while not technically correct (you don't have to subclass NSObject), will probably get you want you want.