How to tell what code is calling a method? - ios

I have a method that's getting called in my iPhone app at an unexpected time, and I can't figure out what code is calling it. Is there any way to find this out from an Objective C method or an Xcode feature? Basically...
- (void)myMethod {
NSLog(#"who just called me?");
}
This method is called from lots of places in my code, so just searching for the method name doesn't narrow it down enough. I could temporarily add an argument to the method and then edit every call to the method to add a unique identifier as the argument, but that would require a lot of edits and then undoing all the edits when I'm done.
Ideally I would find the class and line number of the code that called this method. I don't need to use this info in the method, I just need it for debugging.

You can log the call stack to see from where the method got invoked
- (void)myMethod {
NSLog(#"who just called me? %#", [NSThread callStackSymbols]);
}

If you are running the app through Xcode then simply set a breakpoint in your myMethod and run the app. When the breakpoint is reached, the app will pause and the debugger will show you the stack trace leading to the method call. Then you can see exactly what it going on.
No need to log a stack trace. Look at in real time with the debugger.

Use NSThread +callStackSymbols — you can just log that directly.

Xcode give us a great feature "Break Point" you just need to put the break point in our method and you can see where the control reach.

This is the best I've come up with. Add some code to the method that crashes the app:
- (void)myMethod {
NSLog(#"who just called me?");
[self nonexistentMethod];
}
Then after the app crashes, type bt into the Xcode console to get a backtrace. From there I can see the last few methods that were called before this one. It's ugly but it works. Is there a better way?

Related

Any danger using performselector in objective-c?

I've been stuck for a couple of days with a crash on Crashlytics that says :
libobjc.A.dylib
objc_msgSend
I managed to point out what seems to be the reason of this crash : __NSThreadPerformPerform
With a little search on stack it seems to be linked with performSelector:withObject:afterDelay:
The code I have mentions a delay of 0 all the time. I use this method to call out what we could call "functors" in iOS, by recreating selectors dynamically from an array of strings that I access from a enum state.
And basically it's all the informations I have from this so far, I learned that the afterDelay: makes your call delayed to the next RunLoop. Does it applies as well on performSelector:withObject: or the afterDelay: adds something to the method that causes this?
And, finally, the real question :
Is performSelector:withObject:afterDelay: a good way to make functors, or is it dangerous to use it like this, and should I be doing any other way?
Thanks in advance,
Don't just assume that your object still exists and can perform selector. Test it before!
if ([someObject respondsToSelector:#selector(someSelector)]) {
[someObject performSelector:#selector(someSelector) withObject:nil];
}

CNContactStoreDidChangeNotification multiple times [duplicate]

I am able to observe the CNContactStoreDidChangeNotification when the contact database is changed while the app is in background state. I am pretty sure that only one observer was added to NSNotificationCenter.
The problem is NSNotificationCenter posts MULTIPLE times (2, 3, 5, and even more times) even if I only add one new contact.
Where is the problem?
Make certain you aren't adding the observer multiple times. This can happen without you realizing it if (for example) you call -addObserver from -viewDidLoad or -viewDidAppear in your view controller (as these might get called more than once throughout the life of your application), or from any of the application state callbacks in your app delegate (-applicationDidBecomeActive, -applicationWillResignActive, -applicationDidEnterBackground, -applicationWillEnterForeground, etc).
Wrap the call to -addObserver in a conditional that ensures it can only be called once (set a flag), and put NSLog statements around it so you can see in the debug console if you are getting there more than once. Search your code for other calls to -addObserver that you might have forgotten about.
Call -removeObserver before adding it, just to be sure (making sure to pass the same name and object as when you added it). Calling -removeObserver on an observer that doesn't exist is okay. Note that this is more of a band-aid than a fix - your code should be smart enough to know whether or not you've already added it - but this might help you diagnose the problem).
I just wrote a quick minimal test program that adds an observer (once!) on CNContactStoreDidChangeNotification and I only get the notification once when I add or change a contact. Write a similar test program for yourself and see if you get the same result. If your test program works correctly, then it is likely that your app is doing something you don't expect (and calling -addObserver multiple times).
I had the same problem, the number of times it fired varied between 2 & 3. The solution that worked for me was to set a semaphore variable, set in the handler and reset the semaphore when finished. Wrap the address book processing in an if statement on the semaphore to ignore further calls.
addressBkSemphore is reset to false in buildFrendsAndContacts
- (void)addressBkChange:(NSNotification *)note
{
if (addressBkSemphore == false)
{
addressBkSemphore = TRUE;
[self buildFrendsAndContacts];
}
}
Hope it helps.
You can start a one time execution timer or a dispatch after few seconds and cancel it in case there's a new contacts update within those seconds, thus ensuring that only the timer or dispatch_after triggered by the last update will actually execute (taking into account that all update calls come one after the other within under a sec. difference, as far as I tested)
And btw, I could reproduce the issue only when making change to contacts on the same device with my app. If I change the contacts on another device linked to the same apple account, there was only one update.

Method mysteriously exits execution in the middle to resume the rest of the program?

So i've got this code that tries to find an unused upload name, using the user's email and a number at its end. It does this with a list of uploaded objects we've already collected, the user's email.(upload_name), and the
current number that might be open (it is incremented when a match is found).
The list is not sorted, and it's pretty tricky to sort for a few reasons, so I'm having the method read through the list again if it reaches the end and the upload_number has changed.
- (NSString*)findUnusedUploadNameWithPreviousUploads:(NSMutableArray*)objects withBaseUploadName:(NSString*)upload_name {
previous_upload_number = upload_number;
for (NSString *key in objects) {
// the component of the object name before the first / is the upload name.
NSLog([key componentsSeparatedByString:#"/"][1]);
if ([[key componentsSeparatedByString:#"/"][1]
isEqualToString:([NSString stringWithFormat:#"%#_%ld", S3KeyUploadName1, upload_number])]) {
upload_number++;
NSLog([NSString stringWithFormat:#"upload name: %#_%ld", S3KeyUploadName1, upload_number]);
}
NSLog(#"pang");
}
NSLog(#"ping");
if (previous_upload_number == upload_number) {
return [NSString stringWithFormat:#"%#%ld", upload_name, upload_number];
}
return [self findUnusedUploadNameWithPreviousUploads:objects withBaseUploadName:upload_name];
}
The problem is, the program never reads the "ping". it just leaves the method after the first for loop is done.
Edit: No the NSlogs are fine, you can do simple string OR StringWithFormat.
Edit: Don't mind the unnecessary use of recursion, I did this because the simple way was having the same problem and i wanted to see if a different (albeit unnecessarily recursive) way would share that problem. It does.
Edit: I set a breakpoint in the for loop, and I set a break point at the "ping". It does not reach the ping. It completes the for loop and the ditches the whole thing.
Edit: Please try to help me figure out why it's exiting the the method immediately after the for loop. I'm aware this is stylistically meh, and I promise I'll make it shiny and spotless when it works. =]
Edit: to be clear, the method DOES exit. it does so early I know this because the rest of the program following this method (which is not threaded such that it wouldn't have to wait for it) runs AFTER this for loop, consistently.
There are a couple of possible explanations for the described behavior:
The method never exits. For some reason it blocks or performs infinitely somewhere in the loop. Make sure this is not the case by setting a breakpoint after the place where the message is called (i.e. the place to where it should return).
The method, or some method it calls, throws an exception. While seldom and unsupported in productive Cocoa code it could be some misbehaving 3rd party library or just a simple programmer error, where Cocoa actually does throw. Make sure this does not happen by setting an exception breakpoint in Xcode.
Undefined behavior. This is, sadly, part of official C and heavily exploited by modern compilers. It basically means: Anything can happen, if there's something in your code, where the standard says that the behavior is not defined. One example would be accessing a deallocated object. Another fine reason of undefined behavior can be threads accessing common data in an unsynchronized way.
Other than exceptions there's no explanation for a method to "exit early". If you still can't find the reason I suggest you invest some time to learn the debugger. Single stepping, like Aris suggested, might be a way to find out what's going on.

strange error when reload tableView

I have a very general table view.
when it is refreshed, it will go to fetch list of objects from Parse. Analyze these data in a dispatch_async queue, then refresh table view. Most time, it has no problem, but some time reloadData() crash
Is it crashes because the tableView is reloading data when I call it? (when the tableview is init, reloadData may be called automatically) How to avoid this error? ( there is no error message in console )
EDIT:
I tries to put ?, but does not work
This happens when your tableView (or whatever object you're sending the message to) is nil. So sometime before your async call dispatched this on the main queue, your tableView got dealloacted.
Check this link out for some info:
http://www.touch-code-magazine.com/how-to-debug-exc_bad_access/
You will get EXC_BAD_ACCESS error mostly in the following scenarios:
You are trying to access an object that is not initialized.
You are trying to access an object that no longer exists. Either it’s being released or it’s nil. In ARC mode, make sure you take ownership of the object that you want to use.
You are passing an message to an object that the object doesn’t understand.
It can also happen for bad typecast. Like the lines below where I am trying to access an int with %# in stead of %d.
int myAwesomeInt = 9;
NSLog(#"%#", myAwesomeInt);
How to debug:
Identify what you did that caused the crash. Did it crash while view of a particular view controller didLoad or in a delegate method or on a particular action. That will often help to find the object that is casuing the error.
(In your case look at what specifically happens when you are reloading the table. Do a stack trace line by line and see what your code is doing during a reload)
Most of the time “NSZombies” can help to identify the dead object. You can enable NSZombies by editing your scheme Product -> Edit Scheme -> Diagnostics.
If you still don’t find the root cause then always go backwards from child view controller to parent view controller to see what object needs to be retained or what message needs to be passed properly.
Look into Static Analyzer and Instruments for advanced debugging.
Credit:
The Basic Troubleshooting guide
Hope this helps. Good Luck

Theos instance method calling

I have searched for an answer to this and cannot find one.
How would I call an instance method in the same class I am hooking in my Theos tweak?
If I was using standard Xcode i would use the self method i.e.-
[self method:arg];
But in a theos tweak this says cannot find the method, even if i hook that method.
Example:
%hook classimhooking
-(void)methodimhooking
{
[classimhooking methodiwanttocall];
[self methodiwanttocall];
%orig;
}
-(void)methodiwanttocall
{
%orig;
}
%end
The methodiwanttocall is there and i can hook to it, just not call it.
I have tried adding a new method with %new and calling that but it is not found, i have tried the same with a delay, but it is not found.
I have tried defining a variable of my class and calling that but it doesn't work.
I can also see that you can grab iVars directly, but this doesn't work with methods.
Any ideas would be appreciated.
If you want to call a method on the object you just hooked, you can use performSelector (or performSelector:withObject: if it has an argument), which should be something like that:
[self performSelector:#selector(methodiwanttocall)];
Sorry to dig an old thread. I may have an idea about the issue here. In case anyone with the same issue comes across this.
The problem is that the compiler does not know there is such a method, even there is. The way to deal with it is to import the header at the top of the code.
#import <classimhooking>

Resources