Thread 1: EXEC_BAD_ACCESS (code=1), address=0x6000000000000018) - sprite-kit

Read all of the posts regarding this error being memory related and trying to access something that is no longer there.
Problem: Error pops up at virtually random intervals. It can appear after the first enemy is killed or the Nth enemy is killed. However, it ONLY appears when an enemy is killed.
Testing: Running iOS 8 beta 5, Xcode 6 beta 5 on iPhone 5s.
Code flow:
Enemy SKNodes class instances are created at start of level and stored in NSMutableArray for reference:
Goblin *newGoblin = [[Goblin alloc] initFacingDirection:1];
// set various properties…
[enemyGoblins addObject:newGoblin];
Player’s sword makes contact with enemy:
NSMutableArray *discardedItems = [NSMutableArray array];
for(Goblin *object in enemyGoblins)
{
[object runBloodBurst:true damagePoints:_player.swordDamage];
if(object.goblinHealth < 0)
[discardedItems addObject:object];
}
if([discardedItems count] > 0)
[enemyGoblins removeObjectsInArray:discardedItems];
In the Goblin class, the “die” code is:
if(self.goblinHealth < 0)
{
SKAction *wait0 = [SKAction waitForDuration:1.0];
SKAction *block0 = [SKAction runBlock:^{
[self removeActionForKey:#"animation"];
[self runAction:[_animations goblin_dieLeft]];
}];
SKAction *block1 = [SKAction runBlock:^{
[self removeFromParent];
}];
[self runAction:[SKAction sequence:#[block0, wait0, block1]]];
}
What I’ve tried:
I disabled the “discardedItems” code because I thought ARC might dump the object from memory once the reference was lost and the subsequent Goblin class’ “die animation” would cause the crash but this did not resolve the issue.
I tried zombies and breakpoints but got no useful clues either.
Am I barking up the wrong tree in regards to what I’ve tried or has anyone experienced a similar issue in Beta 5?
EDIT
Here is the backtrace:
(lldb) bt
* thread #1: tid = 0x3264b, 0x000000018cb13434 SpriteKitSKCSprite::update(double) + 404, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x7000000000000018)
frame #0: 0x000000018cb13434 SpriteKitSKCSprite::update(double) + 404
frame #1: 0x000000018cb13440 SpriteKitSKCSprite::update(double) + 416
frame #2: 0x000000018cb13440 SpriteKitSKCSprite::update(double) + 416
frame #3: 0x000000018cacbf28 SpriteKit-[SKScene _update:] + 140
frame #4: 0x000000018cae63f8 SpriteKit-[SKView(Private) _update:] + 568
frame #5: 0x000000018cae3a10 SpriteKit-[SKView renderCallback:] + 764
frame #6: 0x000000018cae0a9c SpriteKit__29-[SKView setUpRenderCallback]_block_invoke + 60
frame #7: 0x000000018cb0d890 SpriteKit-[SKDisplayLink _callbackForNextFrame:] + 272
frame #8: 0x000000010042ca9c libglInterpose.dylib-[DYDisplayLinkInterposer forwardDisplayLinkCallback:] + 168
frame #9: 0x000000018c615b90 QuartzCoreCA::Display::DisplayLinkItem::dispatch() + 32
frame #10: 0x000000018c615a28 QuartzCoreCA::Display::DisplayLink::dispatch_items(unsigned long long, unsigned long long, unsigned long long) + 324
frame #11: 0x00000001897dddc0 IOKitIODispatchCalloutFromCFMessage + 376
frame #12: 0x00000001885dcf34 CoreFoundation__CFMachPortPerform + 180
frame #13: 0x00000001885f1b38 CoreFoundation__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 56
frame #14: 0x00000001885f1a98 CoreFoundation__CFRunLoopDoSource1 + 436
frame #15: 0x00000001885efa18 CoreFoundation__CFRunLoopRun + 1640
frame #16: 0x000000018851d664 CoreFoundationCFRunLoopRunSpecific + 396
frame #17: 0x000000019154f5a4 GraphicsServicesGSEventRunModal + 168
frame #18: 0x000000018ccd6164 UIKitUIApplicationMain + 1488
* frame #19: 0x0000000100165530 CarcerQuestmain(argc=1, argv=0x000000016fdab9d8) + 116 at main.m:16
frame #20: 0x000000019885aa08 libdyld.dylibstart + 4
(lldb)

change
[self runAction:[SKAction sequence:#[block0, wait0, block1]]];
to
[self runAction:[SKAction sequence:#[block0, wait0]] completion:^{
[_self removeFromParent];
}];
I ran in to the same issue when updating IOS7 code to run on IOS8, and using the completion block fixed the issue.

Reading through the comments of your question, I'm not sure if you've solved this problem, and your code snippet isn't complete enough for me to see your issue, but I recently ran into a similar problem and it took me a while to figure out, so I'd post it in case it's helpful to you or some future reader of the post.
You can see my code change here: https://github.com/ik/2048/commit/3ffec547367320c7e179624a14ac5867ed1acea2
Basically what happens is runAction is async. It is executed in the next screen refresh cycle (hence the display link call in your stack trace). So if you call removeSomething after your runAction, it can be executed before the action is run, and you will crash.
At least that's what caught me - I don't know why it never occurred in iOS 7. See code below.
- [self removeFromParentCell]; // Used to call it here - wrong.
SKAction *wait = [SKAction waitForDuration:GSTATE.animationDuration];
SKAction *remove = [SKAction removeFromParent];
- [self runAction:[SKAction sequence:#[wait, remove]]];
+ [self runAction:[SKAction sequence:#[wait, remove]] completion:^{
+ [self removeFromParentCell]; // This is right.
+ }];

After scouring the Apple Support Forums and running the same project on iOS 7, it appears this is a Beta release bug and not faulty code after all.

Related

Swift String rare crash

In my app I have a logger that writes errors and status messages to a string. It's not written to a file, it's just handy to have something to look at when a bug happens without an attached debug session.
The addLog() method is called approx. 0-10 times every 3 seconds and is fairly simple:
every call adds the new addition to the beginning of the string along with the second it has happened
to prevent the string from blowing up in terms of size, if it exceeds 2kb, it will successively cut the "oldest" 100 log characters until it's smaller than 2kb again
The code looks as following:
var logString = ""
func addLog(s : String){
let date = Date()
logString = "\(date.second)\(s).\n\(logString)"
while(logString.count>2000){
logString=String(logString.dropLast(100))
}
}
I've never seen anything wrong with it until today when I received a crash log:
Thread 5 name:
Thread 5 Crashed:
0 libsystem_kernel.dylib 0x00000001c00f5414 __pthread_kill + 8
1 libsystem_pthread.dylib 0x00000001ddc50b50 pthread_kill + 272 (pthread.c:1392)
2 libsystem_c.dylib 0x000000019b5d3b74 abort + 104 (abort.c:110)
3 libsystem_malloc.dylib 0x00000001a1faf49c malloc_vreport + 560 (malloc_printf.c:183)
4 libsystem_malloc.dylib 0x00000001a1faf740 malloc_zone_error + 104 (malloc_printf.c:219)
5 libsystem_malloc.dylib 0x00000001a1f99ed8 free_small_botch + 40 (magazine_small.c:2215)
6 libswiftCore.dylib 0x00000001961103d8 _swift_release_dealloc + 40 (HeapObject.cpp:648)
7 APPNAME 0x00000001046b56a0 AppDelegate.addLog(s:) + 960 (AppDelegate.swift:0)
What's weird about the log itself is that the addLog() function is not in line 0 of my AppDelegate but maybe that's normal to have the wrong line in the crash report.
The only possible explanation for this issue that I can come up with is that there is an issue with thread safety in my function, or that I have missed something regarding the garbage collection in swift. It's very likely that the function is called from different threads at the same time, could that be an issue? Or do I have to get into the objective-c times retain etc. again to resolve this? What can I make out of this crash log?
You must handle all changes in serial queue. The simple modification:
private let queue = DispatchQueue(label: "addlog.queue")
private var logString = ""
func addLog(s : String) {
queue.async { [weak self] in
guard let self = self else { return }
let date = Date()
self.logString = String("\(date.second)\(s).\n\(self.logString)".prefix(2000))
}
}
In your case you can read and write the "logString" parameter from different threads, using serial DispatchQueue for handle all actions with parameter make unavailable to read and write parameter at one moment of time

Embedding Racket static libs in macOS desktop application (Xcode project)

There was an article on the internet about embedding manually built Racket libs into an iOS application. Disregarding the fact that such a possibility is more fun than useful, I've followed instructions and (ta-dah) been able to create a working example (to my surprise!).
Anyway, I was quite more eager to repeat a trick with the macOS Xcode project. There is Racket.framework included in Racket distribution and it works well with gcc (and -framework option) but from Xcode's perspective of view this framework doesn't have valid structure and xcodetools are not able to link to it or moreover codesign.
So I've decided to follow iOS instructions from the article but for macOS. I've built macOS Racket libraries (librktio, libracket and libmzgc) using ./configure without specifying host and
just make
make cgc && make install-cgc
(NB: in the end result was same for both).
I've created interop C source:
#include "scheme.h"
#include "interop.h"
#include "racketmac.c" // <- this is my rkt module made with raco ctool
static int init(Scheme_Env *e, int argc, char *argv[]) {
declare_modules(e);
return 0;
}
int init_racket() {
return scheme_main_setup(1, init, 0, NULL);
}
and header:
#ifndef Interop_h
#define Interop_h
int init_racket(void);
#endif /* Interop_h */
, then added "interop.h" to bridging header and C function call from Swift like:
import Cocoa
final public class RacketInteractor: NSObject {
public override init() {
super.init()
init_racket()
}
}
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
var interactor: RacketInteractor!
func applicationDidFinishLaunching(_ aNotification: Notification) {
interactor = RacketInteractor()
}
// ...
}
Project, macOS Cocoa application, is build-able and runnable. But call of init_racket every single time results in EXC_BAD_ACCESS. Studying stack trace has given me understanding that scheme interpreter is trying to emit "out of memory" error (look for frame #5):
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x10ad2153d)
frame #0: 0x000000010ad2153d
* frame #1: 0x0000000100102814 RacketMapApp`scheme_native_stack_trace at jitstack.c:215:7 [opt]
frame #2: 0x0000000100058f7b RacketMapApp`continuation_marks(p=0x000000010a3b1250, _cont=0x0000000000000000, econt=0x0000000000000000, mc=<unavailable>, prompt_tag=0x000000010a4001d0, who="continuation-marks", just_chain=0) at fun.c:7906:10 [opt]
frame #3: 0x000000010002d565 RacketMapApp`do_raise(arg=0x000000010ac49028, need_debug=1, eb=180654120) at error.c:4606:13 [opt]
frame #4: 0x0000000100028f8a RacketMapApp`scheme_raise_exn(id=17) at error.c:4402:3 [opt]
frame #5: 0x000000010002c4f7 RacketMapApp`scheme_raise_out_of_memory(where=<unavailable>, msg=<unavailable>) at error.c:2541:3 [opt]
frame #6: 0x00000001001a02af RacketMapApp`scheme_malloc_code [inlined] malloc_page(size=<unavailable>) at salloc.c:1047:5 [opt]
frame #7: 0x00000001001a0271 RacketMapApp`scheme_malloc_code(size=35320) at salloc.c:1156 [opt]
frame #8: 0x00000001001035ef RacketMapApp`scheme_generate_one(old_jitter=0x0000000000000000, generate=(RacketMapApp`scheme_do_generate_common at jitcommon.c:3576), data=0x0000000000000000, gcable=0, save_ptr=0x0000000000000000, ndata=0x0000000000000000) at jitstate.c:256:18 [opt]
frame #9: 0x000000010008f593 RacketMapApp`create_native_lambda(lam=0x000000010ac5b348, clear_code_after_jit=1, case_lam=0x0000000000000000) at jit.c:4127:5 [opt]
frame #10: 0x0000000100101f4b RacketMapApp`scheme_jit_closure(code=0x000000010ac5b308, context=0x0000000000000000) at jitprep.c:558:13 [opt]
frame #11: 0x0000000100101abe RacketMapApp`jit_expr(expr=0x000000010a2e3c68) at jitprep.c:0 [opt]
frame #12: 0x0000000100101cd9 RacketMapApp`jit_expr [inlined] define_values_jit(data=<unavailable>) at jitprep.c:301:12 [opt]
frame #13: 0x0000000100101c82 RacketMapApp`jit_expr(expr=0x000000010ac48fe8) at jitprep.c:651 [opt]
frame #14: 0x00000001001020ce RacketMapApp`scheme_jit_linklet(linklet=0x000000010a4bfb88, step=<unavailable>) at jitprep.c:704:9 [opt]
frame #15: 0x00000001001088f4 RacketMapApp`instantiate_linklet_k at linklet.c:0 [opt]
frame #16: 0x000000010004ffd9 RacketMapApp`scheme_top_level_do_worker(k=(RacketMapApp`instantiate_linklet_k at linklet.c:1325), eb=<unavailable>, new_thread=0) at fun.c:1314:11 [opt]
frame #17: 0x000000010002450f RacketMapApp`scheme_basic_env [inlined] place_instance_init(stack_base=<unavailable>, initial_main_os_thread=1) at env.c:501:3 [opt]
frame #18: 0x000000010002436b RacketMapApp`scheme_basic_env at env.c:214 [opt]
frame #19: 0x000000010019f7f8 RacketMapApp`scheme_main_setup [inlined] call_with_basic(data=<unavailable>) at salloc.c:178:16 [opt]
frame #20: 0x000000010019f7f3 RacketMapApp`scheme_main_setup [inlined] do_main_stack_setup(no_auto_statics=<unavailable>, data=<unavailable>) at salloc.c:203 [opt]
frame #21: 0x000000010019f7c3 RacketMapApp`scheme_main_setup [inlined] scheme_main_stack_setup(no_auto_statics=<unavailable>, data=<unavailable>) at salloc.c:337 [opt]
frame #22: 0x000000010019f758 RacketMapApp`scheme_main_setup(no_auto_statics=<unavailable>, _main=(RacketMapApp`init at interop.c:14), argc=0, argv=0x0000000000000000) at salloc.c:187 [opt]
frame #23: 0x00000001000017fb RacketMapApp`#objc RacketInteractor.init() [inlined] RacketMapApp.RacketInteractor.init() -> RacketMapApp.RacketInteractor at RacketInteractor.swift:19:9 [opt]
frame #24: 0x00000001000017bc RacketMapApp`#objc RacketInteractor.init() at <compiler-generated>:15 [opt]
frame #25: 0x00000001000024ed RacketMapApp`#objc AppDelegate.applicationDidFinishLaunching(_:) [inlined] RacketMapApp.RacketInteractor.__allocating_init() -> RacketMapApp.RacketInteractor at <compiler-generated>:0 [opt]
frame #26: 0x00000001000024e2 RacketMapApp`#objc AppDelegate.applicationDidFinishLaunching(_:) [inlined] RacketMapApp.AppDelegate.applicationDidFinishLaunching(self=0x0000600000004320) -> () at AppDelegate.swift:17 [opt]
frame #27: 0x00000001000024e2 RacketMapApp`#objc AppDelegate.applicationDidFinishLaunching(_:) at <compiler-generated>:16 [opt]
frame #28: 0x00007fff3443135f CoreFoundation`__CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
frame #29: 0x00007fff344312f3 CoreFoundation`___CFXRegistrationPost1_block_invoke + 63
frame #30: 0x00007fff34431268 CoreFoundation`_CFXRegistrationPost1 + 372
frame #31: 0x00007fff34430ebe CoreFoundation`___CFXNotificationPost_block_invoke + 97
frame #32: 0x00007fff344007e2 CoreFoundation`-[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1575
frame #33: 0x00007fff343ffc82 CoreFoundation`_CFXNotificationPost + 1351
frame #34: 0x00007fff36a85a02 Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:] + 59
frame #35: 0x00007fff3160b2ff AppKit`-[NSApplication _postDidFinishNotification] + 312
frame #36: 0x00007fff3160b042 AppKit`-[NSApplication _sendFinishLaunchingNotification] + 208
frame #37: 0x00007fff31608103 AppKit`-[NSApplication(NSAppleEventHandling) _handleAEOpenEvent:] + 549
frame #38: 0x00007fff31607d49 AppKit`-[NSApplication(NSAppleEventHandling) _handleCoreEvent:withReplyEvent:] + 688
frame #39: 0x00007fff36ab1226 Foundation`-[NSAppleEventManager dispatchRawAppleEvent:withRawReply:handlerRefCon:] + 308
frame #40: 0x00007fff36ab1090 Foundation`_NSAppleEventManagerGenericHandler + 98
frame #41: 0x00007fff357b5092 AE`___lldb_unnamed_symbol77$$AE + 2172
frame #42: 0x00007fff357b47b9 AE`___lldb_unnamed_symbol76$$AE + 41
frame #43: 0x00007fff357aca27 AE`aeProcessAppleEvent + 449
frame #44: 0x00007fff32fa22b8 HIToolbox`AEProcessAppleEvent + 54
frame #45: 0x00007fff3160215c AppKit`_DPSNextEvent + 1670
frame #46: 0x00007fff31600690 AppKit`-[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1352
frame #47: 0x00007fff315f23ae AppKit`-[NSApplication run] + 658
frame #48: 0x00007fff315c4775 AppKit`NSApplicationMain + 777
frame #49: 0x0000000100001a29 RacketMapApp`main at AppDelegate.swift:12:7 [opt]
frame #50: 0x00007fff6ba967fd libdyld.dylib`start + 1
frame #51: 0x00007fff6ba967fd libdyld.dylib`start + 1
I tried to create static lib with Interop sources and add it to the Xcode project with the same result.
At the same moment, created librktio, libracket and libmzgc are totally OK to be used with gcc cli. So I'm confused because I even don't know how to debug such error properly. Maybe I need to tweak some Xcode build options? Why iOS-ready libraries are working fine while macOS-ready ones aren't? Is there an easier way to embed Racket into the Xcode macOS project (through generating it via CMake, for example)?
EDIT: When building racket3m version, crash message is more clear, for example:
"WARNING: couldn't protect 16384 bytes of page 0x10a350000(os/kern) protection failure"
It's like syscalls for memory allocations just don't give enough resources, and this is weird.
"WARNING: couldn't protect 16384 bytes of page 0x10a350000(os/kern) protection failure"
Occurs when your app is missing the "Allow Unsigned Executable Memory" entitlement. Make sure your app has that and the "Allow JIT" entitlement.
But once you get past that, you'll run into Racket 3m's GC write barrier, which I briefly touch upon in the article. For that to work in debug mode, you'll have to register a signal handler in lldb to pass the expected SIGSEGV when it occurs. Unfortunately, there's an LLDB bug and this doesn't work on arm, but it may work on x86-64.

Why sometimes 'self' isn't available while debugging with lldb?

A lot of time (when it's not every time) I got the following error when I try to print objects on lldb. Is there some build/debug configuration to change or is this an error inside lldb?
(lldb) po userLevel
error: warning: Stopped in an Objective-C method, but 'self' isn't available; pretending we are in a generic context
error: use of undeclared identifier 'userLevel'
error: 1 errors parsing expression
I build with llvm and do not strip debug symbols.
Edit: Here is the backtrace:
(lldb) bt
* thread #1: tid = 0x1c03, 0x001169c5 FanCake-Beta`-[KWUserLevelController addPoints:](, _cmd=0x0029187b, points=15) + 179 at KWUserLevelController.m:53, stop reason = step over
frame #0: 0x001169c5 FanCake-Beta`-[KWUserLevelController addPoints:](, _cmd=0x0029187b, points=15) + 179 at KWUserLevelController.m:53
frame #1: 0x00112172 FanCake-Beta`-[KWEventRealTimeControllergameEngine:hostedGame:didSucceedIn:withScore:](self=0x0b9d7740, _cmd=0x0027a2a7, engine=0x1be5af40, game=0x1be5a850, completionTime=3.59473554800206, score=0) + 421 at KWEventRealTimeController.m:647
frame #2: 0x0007189a FanCake-Beta`__35-[KMCatchEmGameEngine animateStep6]_block_invoke197(, finished='\x01') + 257 at KMCatchEmGameEngine.m:214
frame #3: 0x01990df6 UIKit`-[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 223
frame #4: 0x01983d66 UIKit`-[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 237
frame #5: 0x01983f04 UIKit`-[UIViewAnimationState animationDidStop:finished:] + 68
frame #6: 0x017587d8 QuartzCore`CA::Layer::run_animation_callbacks(void*) + 284
frame #7: 0x03634014 libdispatch.dylib`_dispatch_client_callout + 14
frame #8: 0x036247d5 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 296
frame #9: 0x04737af5 CoreFoundation`__CFRunLoopRun + 1925
frame #10: 0x04736f44 CoreFoundation`CFRunLoopRunSpecific + 276
frame #11: 0x04736e1b CoreFoundation`CFRunLoopRunInMode + 123
frame #12: 0x040367e3 GraphicsServices`GSEventRunModal + 88
frame #13: 0x04036668 GraphicsServices`GSEventRun + 104
frame #14: 0x01945ffc UIKit`UIApplicationMain + 1211
frame #15: 0x000039a8 FanCake-Beta`main(argc=1, argv=0xbffff354) + 94 at main.m:13
frame #16: 0x00002dc5 FanCake-Beta`start + 53
Edit 2: Same thing when I try to print local vars
(lldb) po currentUser
error: variable not available
If I put some NSLog() in the code, the correct value is printing. But not with the po command.
I usually get this error when I have compiler optimization turned on. The compiler will generate code which does not necessarily follow your code logic flow.
Go to your project in the navigator -> Target -> Build settings -> Search for optimization level -> expand optimization level -> select the debug line -> change to none in both columns of your project and target.
Hope this helps.
I was having this problem and it went away when I edited my scheme and set the Run build to Debug. I had set it to AdHoc for testing Push Notifications and that apparently makes LLDB unhappy.
Because it's optimized away. Let's use an example:
void f(int self) {
// Here, "self" is live:Its value is used in the call to NSLog()
NSLog(#"I am %d",self);
// Here, "self" is dead: Its value is never used.
// I could do self=0 or self=self*self and nobody would know.
// An optimizing compiler will typically optimize it away.
// It might still be on the stack (in the parameters passed to NSLog())
// but the compiler shouldn't assume this.
NSLog(#"Another function call: %d", 1);
// If "self" was on the stack, it will probably now have been overwritten.
}
Compilers do a lot of things to make your code faster/smaller; forgetting about variables which are no longer needed is a very common optimization.
As already said in this other question:
In Build Settings, setting Precompile Prefix Header to NO fixed it for me.

[__NSDate objCType]: unrecognized selector

Sometimes I got error saying that unrecognized selector objcType was sent to an NSDate object:
2011-06-11 14:44:51.589 MyApp[354:307] -[__NSDate objCType]:
unrecognized selector sent to instance 0x4b0d5a0
2011-06-11 14:44:51.732 MyApp[354:307] * Terminating app due to
uncaught exception 'NSInvalidArgumentException', reason: '-[__NSDate
objCType]: unrecognized selector sent to instance 0x4b0d5a0'
What I do is loading data from sqLite using Core Data by calling [[self fetchedResultsController] performFetch:&error]. I use a predicate, which ensures that the only (NSManaged)objects having their attribute kickoffTime of type NSDate in a specified range are fetched:
NSDate * fromDate = ...
NSDate * toDate = ...
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"( ( %# <= kickoffTime +0 ) && ( kickoffTime +0 <= %# ) )", fromDate, toDate];
// Add the predicate to the fetchRequest
[[[self fetchedResultsController] fetchRequest] setPredicate:predicate];
NSError *error;
if (![[self fetchedResultsController] performFetch:&error])
{
...
}
I do not really know what the problem might be. I probably misuse the core data predicate in some way, forcing the framework to send the objCType message to NSDate object in order to find out type of the object. Does anybody have some suggestions?
Here is a few things I have observed:
the NSDate object to which is sent the problematic selector is the kickoffTime attribute of my NSManagedObject
it happens pretty randomly so it is not easy to reproduce
the NSDate object to which the unrecognized selector is sent appears to be valid object (I could print it out in gdb)
Here is the top of the stack:
0 CoreFoundation 0x3587a987
__exceptionPreprocess + 114
1 libobjc.A.dylib 0x34a8249d
objc_exception_throw + 24
2 CoreFoundation 0x3587c133
-[NSObject(NSObject) doesNotRecognizeSelector:] + 102
3 CoreFoundation 0x35823aa9 forwarding +
508
4 CoreFoundation 0x35823860
_CF_forwarding_prep_0 + 48
5 Foundation 0x3121ac69
+[_NSPredicateUtilities add:to:] + 40
6 Foundation 0x31221225
-[NSFunctionExpression expressionValueWithObject:context:] + 688
7 Foundation 0x3117e045
-[NSComparisonPredicate evaluateWithObject:substitutionVariables:] +
176
8 Foundation 0x312255fb
-[NSCompoundPredicateOperator
evaluatePredicates:withObject:substitutionVariables:] + 186
9 Foundation 0x3121e43f
-[NSCompoundPredicate evaluateWithObject:substitutionVariables:] + 186
10 Foundation 0x3117df8d -[NSPredicate
evaluateWithObject:] + 16
11 CoreData 0x356e8edf
-[NSManagedObjectContext executeFetchRequest:error:] + 2014
12 CoreData 0x357a041b
-[NSFetchedResultsController performFetch:] + 766
13 MyApp 0x000195ef
-[MatchesCalendarDataSource loadMatchesFrom:to:delegate:] + 138
The objcType is a selector/method of NSValue and its subclasses like NSNumber. That means that the NSDate object is being treated like a NSValue at some point. It most likely happens when the NSDate is being wedged into a mathematical operation which it doesn't support.
In a predicate, a NSDate will often be converted to a NSTimeInterval which is a double. If you log the predicate you have above, the date will resolve something like this:
CAST(335110182.022141, "NSDate") <= kickoffTime + 0 AND kickoffTime + 0 <= CAST(335110182.022141, "NSDate")
... which is the NSDate being cast to a double. That is where your problem comes from. I suspect it arises because the predicate parser cannot always resolve the precedence.
You can probably resolve the problem just by:
(CAST(335110182.022141, "NSDate") <= kickoffTime + 0) AND (kickoffTime + 0 <= CAST(335110182.022141, "NSDate"))
However, the +0 does absolutely nothing in a predicate besides cause problems so I would just lose it.
BTW when you say:
What I do is loading data from sqLite using Core Data by calling
... that suggest that you are thinking of Core Data as an object wrapper for sqlite. It isn't and thinking that way will get you into trouble especially with predicates.

Why does my iPhone app update from App Store fail while upgrading the database?

I've released an app update which does an upgrade of the database ie. executes a script file in the bundle that adds a column to existing table , etc. I've tested this by deploying previous version builds on my device from xcode and then deploying the latest version. The upgrade worked fine.
Yesterday my distribution build got accepted to app store. When I start it up , my nightmare scenario materialized , it fails during DB upgrade! I've checked the distribution build and the upgradeSQL file is there , so it doesn't seem to be a missing resource file all though I'm not sure. I have no idea how I should debug this. What is the difference between a distribution build from app store and a release/debug build deployed from xcode , apart from code signing? Doesn't make sense to me.
This is my crash log and the code that fails:
0 libSystem.B.dylib 0x3141d414 pread + 20
1 libsqlite3.0.dylib 0x303a2154 unixRead + 40
2 libsqlite3.0.dylib 0x303bd7c4 sqlite3PagerAcquire + 3748
3 libsqlite3.0.dylib 0x303c7718 sqlite3BtreeNext + 260
4 libsqlite3.0.dylib 0x303c7b84 sqlite3BtreeNext + 1392
5 libsqlite3.0.dylib 0x304272b8 sqlite3VdbeExec + 38668
6 libsqlite3.0.dylib 0x30428944 sqlite3Step + 504
7 libsqlite3.0.dylib 0x303ecbc4 sqlite3_exec + 600
8 MyApp 0x00046ae4 +[DBUpgradeService executeUpgradeScript:] (DBUpgradeService.m:94)
9 MyApp 0x000469aa +[DBUpgradeService upgradeV1_0ToV1_1] (DBUpgradeService.m:67)
10 MyApp 0x0004687a +[DBUpgradeService upgradeDBIfNecessary] (DBUpgradeService.m:27)
11 MyApp 0x000021ec -[MyAppAppDelegate applicationDidFinishLaunching:] (MyAppAppDelegate.m:49)
12 UIKit 0x30a4ef24 -[UIApplication performInitializationWithURL:asPanel:] + 160
13 UIKit 0x30a57dec -[UIApplication _runWithURL:] + 644
14 Foundation 0x306945a2 __NSFireDelayedPerform + 326
15 CoreFoundation 0x30269d88 CFRunLoopRunSpecific + 2642
16 CoreFoundation 0x30269320 CFRunLoopRunInMode + 44
17 GraphicsServices 0x31567e58 GSEventRunModal + 268
18 UIKit 0x30a4fa6c -[UIApplication _run] + 520
19 UIKit 0x30a591d0 UIApplicationMain + 1132
20 MyApp 0x00002090 main (main.m:20)
21 MyApp 0x0000202c start + 44
+ (BOOL) executeUpgradeScript:(NSString*) scriptName{
NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
NSString *scriptPath = [resourcePath stringByAppendingPathComponent:scriptName];
NSString* upgradeScript = [NSString stringWithContentsOfFile:scriptPath];
NSArray* lines = [upgradeScript componentsSeparatedByString:#"\n"];
//begin transaction
NSString* begin = [NSString stringWithString:#"BEGIN TRANSACTION"];
sqlite3_exec([DatabaseManager getDatabase], begin.UTF8String , nil , nil , nil);
BOOL failed = NO;
for( NSString* line in lines) {
const char *sql = line.UTF8String;
char* error = nil;
sqlite3_exec([DatabaseManager getDatabase], sql , nil , nil , &error); //THIS LINE FAILS
if(error != nil) {
NSLog([NSString stringWithCString:error]);
failed = YES;
break;
}
}
if(failed){
return NO;
}
else{
NSString* commit = [NSString stringWithString:#"COMMIT"];
sqlite3_exec([DatabaseManager getDatabase], commit.UTF8String , nil , nil , nil);
return YES;
}
}
If the upgrade of the DB takes to long time in the launch phase an app can be kicked out.
One way to resolve such a problem could be to put the upgrade in a NSThread
- (void)upgradeSomething:(id)sender
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Do something here that takes time
// and maybe signal when done with some flag or thing...
[pool release];
}
- (void)awakeFromNib
{
// The usual stuff
// and detach a NSThread for upgrade
[NSThread detachNewThreadSelector:#selector(upgradeSomething:)
toTarget:self
withObject:nil]
}
Read here for reason for keeping the event loop active.
You aren't allowed to modify files in your application bundle (see epatel's link). As part of your build process, the app gets signed, and modifying files in the bundle will break the signature.
You should be using your application's document directory. You should replace your resourcePath assignment with:
NSString *resourcePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];