I have a crash log for my current iPhone app which is symbolicated, but I am having trouble deciphering what the problem is still.
The basic issue is that on certain devices (particularly older ones) my app with crash back to the home screen. It appears to be when a user comes back to my game after a while - which initiates a login process to the Game Center. I have pasted the relevant part of the crash log below:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x2e000000
Crashed Thread: 0
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 libobjc.A.dylib 0x37c11f7e objc_msgSend + 22
1 Transfer Quiz 0x000023c4 -[GameCenterManager callDelegate:withArg:error:] (GameCenterManager.m:113)
2 Transfer Quiz 0x0000230c __60-[GameCenterManager callDelegateOnMainThread:withArg:error:]_block_invoke_0 (GameCenterManager.m:103)
3 libdispatch.dylib 0x346fdc52 _dispatch_call_block_and_release + 6
4 libdispatch.dylib 0x346ffee0 _dispatch_main_queue_callback_4CF$VARIANT$mp + 188
5 CoreFoundation 0x358432a6 __CFRunLoopRun + 1262
6 CoreFoundation 0x357c649e CFRunLoopRunSpecific + 294
7 CoreFoundation 0x357c6366 CFRunLoopRunInMode + 98
8 GraphicsServices 0x37462432 GSEventRunModal + 130
9 UIKit 0x332d2cce UIApplicationMain + 1074
10 Transfer Quiz 0x000030d4 main (main.m:16)
11 Transfer Quiz 0x000021a8 start + 32
and here is the following code for GameCenterManager callDelegate:
- (void) callDelegate: (SEL) selector withArg: (id) arg error: (NSError*) err
{
assert([NSThread isMainThread]);
if([delegate respondsToSelector: selector])
{
if(arg != NULL)
{
[delegate performSelector: selector withObject: arg withObject: err];
}
else
{
[delegate performSelector: selector withObject: err];
}
}
else
{
NSLog(#"Missed Method");
}
}
The code was part of a tutorial on an external tutorial website - and I cannot pinpoint the issue that's causing my app to crash here.
Does anyone know of a reason why code is causing the crash? Any help would be much appreciated. I am finding it very hard to replicate the crash on any device and using NSZombies is also not working probably due to my inability to recreate the crash.
Thank you all, in advance.
It seems that the selector you're calling takes 2 arguments: an 'arg' and an 'error'. Now the thing is that if 'arg' is nil, you're calling the selector to one argument only - so the second argument is basically garbage, and when the object on which the selector is called tries to access the second argument, it crashes. All in all, you don't need that if() - always pass both arguments to the selector and let the delegate detect if its first argument is nil.
Related
I faced problem as in title, when I call .toRelative(since:style:locale:) on my date which as string is f.e. "2022-06-07 13:12:06 +0000" my app crashes. Crash stack from Console app prints:
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 SwiftDate 0x10425f4ee specialized static RelativeFormatter.suitableFlavour(inList:forLocale:) + 1230
1 SwiftDate 0x10425e46d specialized static RelativeFormatter.format(date:to:style:locale:) + 1517
2 SwiftDate 0x104252e9b DateRepresentable.toRelative(since:style:locale:) + 507
3 MyApp 0x103f8d8cf 0x103f76000 + 96463
The line where I call that is the last one below:
var locales = Locales.english
let style = RelativeFormatter.timeStyle()
return creationDate.toRelative(style:style, locale: locales)
Maybe is significant that I call that in SwiftUI.
The problem occurs after a few launches on OS X 10.15 and 12.4 at this moment, architecture x86_64.
The error is:
System Integrity Protection: enabled
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_INSTRUCTION (SIGILL)
Exception Codes: 0x0000000000000001, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Termination Reason: Namespace SIGNAL, Code 4 Illegal instruction: 4
Terminating Process: exc handler [830]
Thanks for every help!
I am following the iOS quick start tutorial and I have gotten as far as creating the button to login to SoundCloud but I'm getting this error:
2013-05-01 15:00:44.698 SoundCloudSample[60999:c07] +[SCSoundCloud shared]: unrecognized selector sent to class 0x3a568
2013-05-01 15:00:44.701 SoundCloudSample[60999:c07] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[SCSoundCloud shared]: unrecognized selector sent to class 0x3a568'
* First throw call stack:
(0x192a012 0x174fe7e 0x19b52ad 0x1919bbc 0x191994e 0x2ad0 0x17507cf 0x1757a0d 0x174eaeb 0x174ee22 0x17610e1 0x1763705 0x8c02c0 0x8c0258 0x981021 0x98157f 0x9806e8 0x8efcef 0x8eff02 0x8cdd4a 0x8bf698 0x1da7df9 0x1da7ad0 0x189fbf5 0x189f962 0x18d0bb6 0x18cff44 0x18cfe1b 0x1da67e3 0x1da6668 0x8bcffc 0x1f0d 0x1e35)
libc++abi.dylib: terminate called throwing an exception
(lldb)
- (IBAction) login:(id)sender {
SCLoginViewControllerCompletionHandler handler = ^(NSError *error) {
if (SC_CANCELED(error)) {
NSLog(#"Canceled!");
} else if (error) {
NSLog(#"Error: %# ", [error localizedDescription]);
} else {
NSLog(#"Done");
}
};
[SCSoundCloud requestAccessWithPreparedAuthorizationURLHandler:^(NSURL *preparedURL){
SCLoginViewController *loginViewController;
loginViewController = [SCLoginViewController loginViewControllerWithPreparedURL:preparedURL completionHandler:handler];
[self presentModalViewController:loginViewController animated:YES];
}];
}
I'm not sure exactly what I'm doing wrong since I followed the tutorial.
I'm also confused about the client_id, secret, and redirect URI.
Here is the code for that:
- (void) initialize {
[SCSoundCloud setClientID:#"98e77c3e4da0cc49f2f8e58f278bb813" secret:#"b8311d06a82a8c824b64b8a719479cda" redirectURL:[NSURL URLWithString:#"http://soundcloud.com/connect?client_id=98e77c3e4da0cc49f2f8e58f278bb813&redirect_uri=evesdropmusic://oauth"]];
}
Maybe I overlooked something...
I have found the solution to the problem!
Apparently I think I found a bug in the newest version of XCode.
on the "Other Linker Flags" under the Targets section -- Build Settings, I found that even though I entered the "-ObjC, -all_load", XCode decided not to save those credentials.
The fix is to enter the flags with the (+) - click on them again, then if they go away, enter it again. It should save this time. Sometimes this doesn't occur. I'm not sure why my entries do not remain.
Once I added these again, this fixed the issue.
I'm trying to build a download manager class that packets all the async download (every op has its own thread) operation in an NSOperation subclass to add them later in an NSOperationQueue. The download manager class (a singleton) also exposes few methods to work on the queue and cancel operations that matches some requirements. Those are steps to start creating kind of a Class Cluster(Abstract Factory) that returns different kinds of NSOperation for different types of common operation (upload, download,parse, etc).
The class seems to work pretty well with download operations, but if in the middle of those operations I call a method for cancel an operation, the operation is successfully cancelled but the app crashes few operation later. If I don't cancel any operations everything works fine. All operations are observed using KVO.
The method that remove the operation looks like that:
- (void) cancelDownloadOperationWithID:(NSString *)aUUID{
#synchronized(self){
[self.dowloadQueue setSuspended:YES]; //downloadQueue is an NSOperationQueue
NSArray * downloadOperations = [self.dowloadQueue operations];
NSPredicate * aPredicate = [NSPredicate predicateWithFormat:#"SELF.connectionID == %#",aUUID]; //SELF is the signleton instance of the download manager
NSArray * filteredArray = [downloadOperations filteredArrayUsingPredicate:aPredicate];
if ([filteredArray count]==0) {
[self.dowloadQueue setSuspended:NO];
return;
}
[filteredArray makeObjectsPerformSelector:#selector(cancel)];
NSLog(#"Cancelled %d operations",[filteredArray count]);
[self.dowloadQueue setSuspended:NO];
}
}
The crash log is pretty incomprehensible but is a BAD_EXC_ACCESS (a zombie perhaps), notice that I'm under ARC.
0x00a90ea8 <+0393> jle 0xa90d9f <____NSOQSchedule_block_invoke_0+128>
0x00a90eae <+0399> mov -0x38(%ebp),%ecx
0x00a90eb1 <+0402> mov -0x34(%ebp),%esi
0x00a90eb4 <+0405> mov (%esi,%ecx,1),%ecx
0x00a90eb7 <+0408> mov -0x40(%ebp),%esi
0x00a90eba <+0411> cmpb $0x0,(%ecx,%esi,1)
0x00a90ebe <+0415> jne 0xa90d9f <____NSOQSchedule_block_invoke_0+128>
0x00a90ec4 <+0421> mov (%edi,%eax,1),%esi
0x00a90ec7 <+0424> mov (%esi,%edx,1),%ebx
0x00a90eca <+0427> mov %ebx,-0x2c(%ebp)
0x00a90ecd <+0430> mov -0x44(%ebp),%ebx
0x00a90ed0 <+0433> cmpl $0x50,(%esi,%ebx,1)
0x00a90ed4 <+0437> mov %edi,%ebx
0x00a90ed6 <+0439> jne 0xa90e96 <____NSOQSchedule_block_invoke_0+375>
0x00a90ed8 <+0441> mov -0x48(%ebp),%ebx
0x00a90edb <+0444> cmpb $0x0,(%esi,%ebx,1)
0x00a90edf <+0448> mov %edi,%ebx
0x00a90ee1 <+0450> je 0xa90e96 <____NSOQSchedule_block_invoke_0+375>
Can some one give me suggestion about it?
Thanx Andrea
Well the answer was pretty simple. In the overridden -cancel method of the NSOperation subclass I was setting both the finished and executing vars triggering the proper KVO callbacks. The problem is that an operation stays in the NSOperationQueue even if it is cancelled, when the queue tries to launch the -start method on an NSOperationQueue that has triggered its KVO callback it crashes.
The work around is as follows: If the operation was cancelled while it was not executing, you must set the finish var to YES right after the start method implementation, otherwise if it was executing it's ok to set finished to YES and executing to NO.
The accepted answer works for me. Just to help clear this up in case anybody else runs into it, I also experienced this crash by setting isFinished improperly inside of my - cancel, before an async operation had begun executing.
Rather than doing that, I switched my - cancel to only change isFinished if the operation was already isExecuting, then in - start I set isFinished immediately as suggested here. Voilà, crash gone.
Here's a piece in swift using two previous answers:
override func cancel() {
super.cancel()
if executing {
executing = false
finished = true
}
task.cancel()
}
override func start() {
if cancelled {
finished = true
return
}
executing = true
main()
}
override func main() {
task.resume()
}
EDIT: Issue has been solved(partially):It is a simulator bug. I've compiled and tested this on two devices with iOS 3.1.3 and 4.0. The exception was handled correctly. Be careful, the simulator is your enemy!
this is driving me crazy. I don't know how to enable exception handling in my project. Look at the code and debugger output below.
My Goal is to catch the exception, not correcting the code so the exception is handled and the app doesn't crash.
I'm using XCode 3.2.3, iPhone SDK 4 final. I have just created a simple view based iPhone App to test this.
I have looked in my project settings and yes the switch "Enable Objective-C Exceptions" is checked. I am using GCC 4.2.
When I look at the build process in detail the compiler flag -fno-objc-exceptions is not within the list of arguments!
What am I missing here?
Thanks in advance
Nick
NSArray * foo = [[NSArray alloc] init];
#try {
NSLog(#"trying...");
[foo objectForKey:#"yeah"];
}
#catch (NSException * e) {
NSLog(#"catching %# reason %#", [e name], [e reason]);
}
#finally {
NSLog(#"finally");
}
leads to
trying...
-[__NSArrayI objectForKey:]: unrecognized selector sent to instance 0x5d5f780
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI objectForKey:]: unrecognized selector sent to instance 0x5d5f780'
*** Call stack at first throw:
(
0 CoreFoundation 0x02393919 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x024e15de objc_exception_throw + 47
2 CoreFoundation 0x0239542b -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x02305116 ___forwarding___ + 966
4 CoreFoundation 0x02304cd2 _CF_forwarding_prep_0 + 50
...
)
terminate called after throwing an instance of 'NSException'
Whether the catch nor the finally block is ever reached.
Quote from How do I catch global exceptions? :
"objc_exception_throw is not an exception. It is the function that throws Objective-C exceptions. Similarly, EXC_ARITHMETIC is not an Objective-C exception; it is a Mach (kernel) exception, meaning that your app tried to do something completely invalid. – Peter Hosey May 14 at 9:14"
That thread does have a link to a solution for your problem though, it appears. The link goes to http://www.restoroot.com/Blog/2008/10/20/crash-reporter-for-iphone-applications-part-2/ which looks a little risky, but if it works, it might be worth it for you.
There are bug reports related to this, e.g.: http://www.openradar.me/8081169 (posted earlier this month)
(Updated to summarize information from comments below.)
If I understand your problem right.
Your Try/ catch block is working correctly.
It is trying to run your code, and catches an error.
You need to decide what to do when it catches an error and code for it within the block.
I normally do that in the CATCH part. As the finally bit will execute regardless of an exception or not being thrown.
Your example code is catching the NSException exception but not the one being thrown, NSInvalidArgumentException. You might have better luck if you look for that specific exception.
NSArray * foo = [[NSArray alloc] init];
#try {
NSLog(#"trying...");
[foo objectForKey:#"yeah"];
}
#catch (NSInvalidArgumentException *e) {
NSLog(#"Invalid argument called.");
}
#catch (NSException * e) {
NSLog(#"catching %# reason %#", [e name], [e reason]);
}
#finally {
NSLog(#"finally");
}
I don't have any way of testing it myself right now, though.
See http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocExceptionHandling.html for more information.
I'm trying to use NSAssert throughout my iPhone app so that if an unexpected condition occurs, the application fails-fast and crashes with a meaningful message in the crash log.
This works fine if the failing NSAssert is on the main thread, as it raises NSInternalInconsistencyException by default which is uncaught and stops execution. But I'm also doing processing in background threads, in which case the NSAssert just aborts the thread, but the programming keeps running.
My current solution is to catch and rethrow the exception in the main thread (in this case, NSOperation's main method):
- (void)main {
#try {
int x = 14;
...
NSAssert1(x > 20, #"x should be greater than 20, was %d", x);
...
}
#catch (NSException *e) {
[e performSelectorOnMainThread:#selector(raise) withObject:nil waitUntilDone:YES];
}
}
Is there a better way? Perhaps using a custom NSAssertionHandler?
I know I could just use C's assert with a static annotation:
assert(x > 20 && "x should be greater than 20");
But this doesn't allow me to show what the actual failing value of x is.
You can replace the NSAssert with a test code followed by an exception raise. This way, if the assertion failed, an exception will be thrown, catched by the #catch block and re-raised on the main thread.
Note: You can even define a C macro, in order to provide a compact form.