Compiler optimization causing EXC_BAD_ACCESS on class property - objective-c

This is strange. Whenever I enable LLVM compiler optimization (-O/-O1 or higher) I get an EXC_BAD_ACCESS error when a property on my class is accessed. The property is accessed earlier in the code flow without a problem, but at "some point" (I know, it's vague) the app crashes.
I've looked at several other Stack Overflow questions re: strict aliasing but don't see (or understand) where I may be breaking that in my code. Here's the offending class: (crash indicated near the end of the class)
#import "MessageManager.h"
#import "NSURL+Additions.h"
#import "NSString+Guid.h"
static MessageManager *_instance = NULL;
#interface MessageManager ()
#property (nonatomic, strong) NSMutableDictionary *listeners;
#property (nonatomic, strong) NSMutableDictionary *senders;
#end
#implementation MessageManager
#synthesize listeners, senders;
+ (MessageManager *) getInstance
{
#synchronized(self)
{
if (self == [MessageManager class] && _instance == NULL) {
_instance = [[self alloc] init];
_instance.listeners = [NSMutableDictionary dictionary];
_instance.senders = [NSMutableDictionary dictionary];
}
}
return (_instance);
}
#pragma mark
#pragma mark Senders
- (void) addMessage:(Message *)message sender:(void (^) ())sender callback:(void (^) (Message *))callback
{
[self addMessage:message sender:sender callback:callback sendImmediately:NO];
}
- (void) addMessage:(Message *)message sender:(void (^) ())sender callback:(void (^) (Message *))callback sendImmediately:(BOOL)sendNow
{
message.id = [NSString stringWithGuid];
[senders setObject:[NSDictionary dictionaryWithObjectsAndKeys:message, #"message", [sender copy], #"sender", nil] forKey:message.id];
// note: callbacks use the message id and not the key, so that they remain tied to the message and not other keyed events
if (callback) [self registerListener:callback forKey:message.id];
if (sendNow) {
message.isSent = YES;
sender();
}
}
- (void) sendAll
{
[self sendAllForTags:nil];
}
- (void) sendAllForTags:(NSArray *)tags
{
typedef void (^SenderBlock) ();
[senders enumerateKeysAndObjectsUsingBlock:^(NSString *messageId, id wrapper, BOOL *stop) {
Message *message = (Message *)[(NSDictionary *)wrapper objectForKey:#"message"];
id sender = [(NSDictionary *)wrapper objectForKey:#"sender"];
BOOL validTag;
if (tags && tags.count) {
if (message.tags.count) {
validTag = false;
for (NSString *tag in tags) {
if ([message.tags containsObject:tag]) {
validTag = true; // found match! ok to send.
break;
}
}
} else validTag = false; // tags specified, but none in message, never send
} else validTag = true; // no tags specified, always send
if ((!message.isSent || message.isRepeatable) && validTag) {
message.isSent = YES;
((SenderBlock)sender)(); // send message!
}
}];
}
#pragma mark
#pragma mark Listeners
- (void) registerListener:(void (^) (Message *))listener forKey:(NSString *)key
{
if (![listeners objectForKey:key]) {
[listeners setObject:[NSMutableArray array] forKey:key];
}
[(NSMutableArray *)[listeners objectForKey:key] addObject:listener];
}
- (BOOL) handleOpenURL:(NSURL *)url
{
Message *message = [[Message alloc] initWithJson:[[url queryParams] objectForKey:#"message"]];
NSLog(#"%#", listeners); // <<<<----- CRASH HAPPENS HERE (or the first place in this method that "listeners" is referenced)
NSMutableArray *keyedListeners = (NSMutableArray *)[listeners objectForKey:message.key];
typedef void (^ListenerBlock)(Message *);
for (ListenerBlock keyedListener in keyedListeners) {
keyedListener(message);
}
return YES;
}
#end
NOTE: registerListener:forKey: is called several times BEFORE handleOpenUrl: gets called, without any error, even though it references the "listeners" property.
For context, this is part of a messaging framework I created that allows sending and receiving messages and events.
EDIT: Stack trace
0 MyApp 0x00026206 testflight_backtrace + 158
1 MyApp 0x00026e30 TFSignalHandler + 244
2 libsystem_c.dylib 0x36fc67ec _sigtramp + 48
3 MyApp 0x00024f7c -[MessageManager handleOpenURL:] (MessageManager.m:112)
4 MyApp 0x0001c29a -[WebViewController webView:shouldStartLoadWithRequest:navigationType:] (WebViewController.m:327)
5 UIKit 0x32492482 -[UIWebView webView:decidePolicyForNavigationAction:request:frame:decisionListener:] + 182
6 CoreFoundation 0x352cf7e3 __invoking___ + 67
7 CoreFoundation 0x3522a7b0 -[NSInvocation invoke] + 160
8 CoreFoundation 0x3522a3ce -[NSInvocation invokeWithTarget:] + 50
9 WebKit 0x338b1e0c -[_WebSafeForwarder forwardInvocation:] + 252
10 CoreFoundation 0x352cea82 ___forwarding___ + 666
11 CoreFoundation 0x3522964f _CF_forwarding_prep_0 + 47
12 CoreFoundation 0x352cf7e3 __invoking___ + 67
13 CoreFoundation 0x3522a7b0 -[NSInvocation invoke] + 160
14 WebCore 0x37060648 _ZL11SendMessageP12NSInvocation + 24
15 WebCore 0x37073b44 _ZL20HandleDelegateSourcePv + 80
16 CoreFoundation 0x352a0ad2 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 14
17 CoreFoundation 0x352a029e __CFRunLoopDoSources0 + 214
18 CoreFoundation 0x3529f044 __CFRunLoopRun + 652
19 CoreFoundation 0x352224a4 CFRunLoopRunSpecific + 300
20 CoreFoundation 0x3522236c CFRunLoopRunInMode + 104
21 GraphicsServices 0x3651e438 GSEventRunModal + 136
22 UIKit 0x32318e7c UIApplicationMain + 1080
23 MyApp 0x0001aa32 main (main.m:34)
24 MyApp 0x0001a9e7 start + 39

I think it is the blocks you are not correctly copying into the collection (listeners). Look at this question: Keep blocks inside a dictionary
There is a a very good write up on why you need to do this

Related

UIAlertView crash private method on iOS7

The stack is as below, how to fix this crash ?
It is only in iOS7 and why there is uitableview in the stack?
0 libobjc.A.dylib objc_msgSend + 5
1 UIKit -[UIAlertView(Private) modalItem:shouldDismissForButtonAtIndex:] + 62
2 UIKit -[_UIModalItemsCoordinator _notifyDelegateModalItem:tappedButtonAtIndex:] + 94
3 UIKit -[_UIModalItemAlertContentView tableView:didSelectRowAtIndexPath:] + 894
4 UIKit -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 1078
5 UIKit -[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 214
6 UIKit _applyBlockToCFArrayCopiedToStack + 316
7 UIKit _afterCACommitHandler + 430
8 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 20
- (id)initWithIdentifier:(LTAlertMsgIdentifier)alertIdentifier
delegate:(id /*<UIAlertViewDelegate>*/)delegate
cancelButtonTitle:(NSString *)cancelButtonTitle
otherButtonTitles:(NSString *)otherButtonTitles, ... {
LTAlertMsgManager *sharedAlertMsgMgr = [LTAlertMsgManager shareAlertManageInstance];
NSString *strMsg = [sharedAlertMsgMgr getLTAlertMsgByAlertID:alertIdentifier];
if ([NSString isBlankString:strMsg]){
// alert is invalid, if alert message is empty
return nil;
}
NSString *strTitle = [sharedAlertMsgMgr getLTAlertTitleByAlertID:alertIdentifier];
if (self = [super initWithTitle:([NSString isBlankString:strTitle] ? nil : strTitle)
message:strMsg
delegate:delegate
cancelButtonTitle:cancelButtonTitle
otherButtonTitles:nil]){
va_list args;
va_start(args, otherButtonTitles);
for (NSString *arg = otherButtonTitles; arg != nil; arg = va_arg(args, NSString*))
{
[self addButtonWithTitle:arg];
}
va_end(args);
}
NSLog(#"cancel button index - %d", self.cancelButtonIndex);
return self;
}
The buttons in the UIAlertView are implemented using a UITableView. That's why tapping a button triggers a tableView:didSelectRowAtIndexPath.
Typical problems causing such errors are:
Alert not displayed from the main thread
Delegate already deallocated (make sure the alert delegate is retained somewhere for the entire life of the alert).
See iOS 7 bug or my bug in UIAlertView
UIAlertView delegate is
#property(nonatomic, assign) id delegate, so ensure alertView.delegate = nil when delegate is dealloced.

-[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (myCustomClass)

I'm new to objective-c and cocoa, and trying to create a document based application that saves and loads a custom class to and from the filesystem. My custom class that conforms to nscoding protocol is as follow:
NSString *const description = #"description";
#implementation PhotoItem
#synthesize description = _description;
-(id)init {
if(self = [super init]){
self.description = #"";
}
return self;
}
/* serializing into file */
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.description forKey:description];
}
/* deserializing */
- (id)initWithCoder:(NSCoder *)aDecoder {
self.description = [aDecoder decodeObjectForKey:description];
return self;
}
and my document:
#implementation AMRDocument
#synthesize imgMainImage = _imgMainImage, lblCreationDate = _lblCreationDate, photo=_photo,
txtDescription = _txtDescription;
- (id)init
{
self = [super init];
if (self) {
self.photo = [[PhotoItem alloc] init];
}
return self;
}
- (NSString *)windowNibName
{
return #"AMRDocument";
}
- (void)windowControllerDidLoadNib:(NSWindowController *)aController
{
NSLog(#"windowControllerDidLoadNib");
[super windowControllerDidLoadNib:aController];
// self.imgMainImage.image = self.photo.image;
[self.txtDescription setString: self.photo.description];
}
+ (BOOL)autosavesInPlace
{
return YES;
}
#pragma mark -saving and loading
- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError
{
// self.photo.image = self.imgMainImage.image;
// return [NSKeyedArchiver archivedDataWithRootObject:self.photo];
self.photo.description = self.txtDescription.string;
NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject:self.photo];
return archivedData;
}
- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError
{
self.photo = [NSKeyedUnarchiver unarchiveObjectWithData:data];
return YES;
}
- (void)windowWillClose:(NSNotification *)notification {
}
- (IBAction)archiveClicked:(id)sender {
self.photo = [NSKeyedUnarchiver unarchiveObjectWithFile:[#"~/desktop/myphoto1.photo"
stringByExpandingTildeInPath]];
[self.txtDescription setString:self.photo.description];
}
- (IBAction)archiveClicked:(id)sender {
self.photo.description = self.txtDescription.string;
[NSKeyedArchiver archiveRootObject:self.photo toFile:[#"~/desktop/myphoto1.photo"
stringByExpandingTildeInPath]];
}
#end
As you can see I've created two actions called archiveClicked, and unarchiveClicked, one for writing and the other for reading from the file.
It works perfectly fine.
When I'm saving the document using command+s, it can also successfully writes to the file, or at least no exception is thrown then. But when I'm trying to open up the saved file, it'll give me following exception in a popup instead of running the application and loads from the disk.
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Application Specific Information:
*** Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: '*** -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (PhotoItem)'
terminate called throwing an exception
abort() called
Application Specific Backtrace 1:
0 CoreFoundation 0x00007fff8f715b06 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff912f03f0 objc_exception_throw + 43
2 CoreFoundation 0x00007fff8f7158dc +[NSException raise:format:] + 204
3 Foundation 0x00007fff98a1e8c3 _decodeObjectBinary + 2559
4 Foundation 0x00007fff98a1dd24 _decodeObject + 226
5 Foundation 0x00007fff98a90df3 +[NSKeyedUnarchiver unarchiveObjectWithData:] + 92
6 DocumentBasedApp 0x0000000108e49a11 -[AMRDocument readFromData:ofType:error:] + 113
7 AppKit 0x00007fff8d764527 -[NSDocument readFromURL:ofType:error:] + 546
8 AppKit 0x00007fff8d365348 -[NSDocument _initWithContentsOfURL:ofType:error:] + 135
9 AppKit 0x00007fff8d364ff4 -[NSDocument initWithContentsOfURL:ofType:error:] + 262
10 AppKit 0x00007fff8d78d765 -[NSDocumentController makeDocumentWithContentsOfURL:ofType:error:] + 332
11 AppKit 0x00007fff8d78ce7f __block_global_12 + 230
12 AppKit 0x00007fff8d78ca1b __block_global_8 + 955
13 AppKit 0x00007fff8d78bdba -[NSDocumentController _openDocumentWithContentsOfURL:usingProcedure:] + 593
14 AppKit 0x00007fff8d78c655 __block_global_7 + 273
15 libdispatch.dylib 0x00007fff926b4f01 _dispatch_call_block_and_release + 15
16 libdispatch.dylib 0x00007fff926b10b6 _dispatch_client_callout + 8
17 libdispatch.dylib 0x00007fff926b60c8 _dispatch_main_queue_callback_4CF + 275
18 CoreFoundation 0x00007fff8f6b7b4c __CFRunLoopRun + 1644
19 CoreFoundation 0x00007fff8f6b70e2 CFRunLoopRunSpecific + 290
20 HIToolbox 0x00007fff8df91eb4 RunCurrentEventLoopInMode + 209
21 HIToolbox 0x00007fff8df91b94 ReceiveNextEventCommon + 166
22 HIToolbox 0x00007fff8df91ae3 BlockUntilNextEventMatchingListInMode + 62
23 AppKit 0x00007fff8d44c533 _DPSNextEvent + 685
24 AppKit 0x00007fff8d44bdf2 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 128
25 AppKit 0x00007fff8d4431a3 -[NSApplication run] + 517
26 AppKit 0x00007fff8d3e7bd6 NSApplicationMain + 869
27 DocumentBasedApp 0x0000000108e49652 main + 34
28 libdyld.dylib 0x00007fff8d2647e1 start + 0
I've actually created the actions to check the correctness of my nscoding functions and it seems to be working fine, but have no clue, and cannot find anything related to my issue.
Appreciate any help. Needless to say this is a part of my homework.
Edit:
name of this application is "PhotoManager". Earlier I had another document based app called "DocumentBasedApp", and the exception starts with :
Process: DocumentBasedApp [4852]
Path: /Users/USER/Library/Caches/*/DocumentBasedApp.app/Contents/MacOS/DocumentBasedApp
Identifier: com.cjcoax.DocumentBasedApp
Version: 1.0 (1)
Code Type: X86-64 (Native)
Parent Process: launchd [132]
User ID: 501
Your initWithCoder: needs to call [super init];.
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self) {
self.description = [aDecoder decodeObjectForKey:description];
}
return self;
}
The serialized version of MyCustomClass differs from the current version in your code, probably due to changes during development.
/Users/USER/Library/Caches/*/DocumentBasedApp.app/Contents/MacOS/DocumentBasedApp
Deleting the Cache directory got rid of the old serialized data.
Finally solved, I delete everything from the cache as I could not find following path:
/Users/USER/Library/Caches/*/DocumentBasedApp.app/Contents/MacOS/DocumentBasedApp
and it started working! Bizarre!
I had another problem with NSCoder's decodeObjectForKey method while using FXForm - it crashed without any explanation.
- (id)initWithCoder:(NSCoder *)decoder
{
if (self = [super init]) {
self.someObject = [decoder decodeObjectForKey:#"someObject"];
}
return self;
}
The reason was in memory issues. Commonly, looks like when there is no explanation of a bug in logs, it means, it's a memory issue. I forgot to use correct property attribute - copy. I used assign instead. This is correct code:
#interface MyClass : : NSObject <FXForm, NSCoding>
#property (nonatomic, copy) SomeClass *someObject;
#end
Just in case somebody meets this problem too.

EXC_BAD_ACCESS when setting scalar property of Core Data object (IOS 5)

I am running the following code in the IOS 5.1 simulator:
Table* sparkFront =
[NSEntityDescription insertNewObjectForEntityForName:#"Table"
inManagedObjectContext:_context];
NSLog(#"%#", sparkFront);
NSEntityDescription* entity = [NSEntityDescription entityForName:#"Table"
inManagedObjectContext:_context];
NSDictionary* dict = [entity propertiesByName];
for (NSObject* key in [dict allKeys])
{
NSLog(#"%#", key);
}
sparkFront.columnValuesAddress = 0x606;
This code crashes with EXC_BAD_ACCESS on the last line. The Table object is a Core Data object implemented as follows:
#interface Table : NSManagedObject
#property (nonatomic) int32_t columnValuesAddress;
#end
I know Core Data doesn't natively do scalar types, but this is an IOS 5+ only app, and I was under the impression the un/boxing was done automatically. The output of the above code before the crash shows that my context and entity are good:
2012-07-20 22:17:52.714 otest[95147:7b03] <NSManagedObject: 0x9c87b20> (entity: Table; id: 0x9c86a80 <x-coredata:///Table/t2C0D90D5-E381-4BD0-B65D-8FC83C6D50DB2> ; data: {
columnValuesAddress = 0;
})
2012-07-20 22:17:52.716 otest[95147:7b03] columnValuesAddress
After the crash, the problem report shows the following:
Application Specific Information:
objc_msgSend() selector name: isNSNumber__
Simulator libSystem was initialized out of order.
Thread 0 Crashed:
0 libobjc.A.dylib 0x00635098 objc_msgSend + 12
1 CoreData 0x05c2e833 _PFManagedObject_coerceValueForKeyWithDescription + 483
2 CoreData 0x05bfe3d1 _sharedIMPL_setvfk_core + 209
3 CoreData 0x05c16687 _svfk_0 + 39
4 ECMCalTests 0x0187f8f1 -[ECMCalTests testInsertRecords] + 849 (ECMCalTests.m:73)
5 CoreFoundation 0x003f74ed __invoking___ + 29
6 CoreFoundation 0x003f7407 -[NSInvocation invoke] + 167
7 SenTestingKit 0x201039c4 -[SenTestCase invokeTest] + 184
8 SenTestingKit 0x20103868 -[SenTestCase performTest:] + 183
9 SenTestingKit 0x201034a9 -[SenTest run] + 82
10 SenTestingKit 0x20106db2 -[SenTestSuite performTest:] + 106
11 SenTestingKit 0x201034a9 -[SenTest run] + 82
12 SenTestingKit 0x20106db2 -[SenTestSuite performTest:] + 106
13 SenTestingKit 0x201034a9 -[SenTest run] + 82
14 SenTestingKit 0x20105e97 +[SenTestProbe runTests:] + 174
15 CoreFoundation 0x00492d51 +[NSObject performSelector:withObject:] + 65
16 otest 0x0000231c 0x1000 + 4892
17 otest 0x000025be 0x1000 + 5566
18 otest 0x00002203 0x1000 + 4611
19 otest 0x00001f8d 0x1000 + 3981
20 otest 0x00001f31 0x1000 + 3889
What am I doing wrong?
UPDATE: I implemented the setter/getter for the property according to the core data tutorial. It still crashes. It never hits a breakpoint in the setter so it is crashing before it even calls the setter. Am I hitting a bug in Apple's code?
#interface Table : NSManagedObject
{
int32_t columnValuesAddress;
}
#property (nonatomic) int32_t columnValuesAddress;
#end
#implementation Table
- (int32_t)columnValuesAddress
{
[self willAccessValueForKey:#"columnValuesAddress"];
int32_t address = columnValuesAddress;
[self didAccessValueForKey:#"columnValuesAddress"];
return address;
}
- (void)setColumnValuesAddress:(int32_t)address
{
[self willChangeValueForKey:#"columnValuesAddress"];
columnValuesAddress = address;
[self didChangeValueForKey:#"columnValuesAddress"];
}
- (void)setNilValueForKey:(NSString *)key
{
if ([key isEqualToString:#"columnValuesAddress"])
{
self.columnValuesAddress = 0;
}
else
{
[super setNilValueForKey:key];
}
}
#end
In the entity editor, you need to set your class. It is set for you when you create the core data class file with the file template. I created a class file without the template and thus the class wasn't set, so I was getting these errors. It will only auto box and un-box if it can see the class and see that you have it specified as assign.
I created a brand new project, created the model again from scratch, and copied over the test code from the old project. This new project works fine. I don't know why the old project doesn't work but at least there is a solution.

iOS Stack Trace Mystery, ABRecordCopyValue Is Suspect

I'm currently using TestFlight in order to get remote crash reports on a beta version of our app. I've received a stack trace, however I'm not quite sure how to narrow down the problem. Here's the report I've received:
0 Holler 0x0003f2a1 Holler + 254625
1 Holler 0x0003f6b7 Holler + 255671
2 libsystem_c.dylib 0x344da72f _sigtramp + 42
3 AppSupport 0x34dfc58d CPRecordCopyProperty + 12
4 AddressBook 0x33e333bf ABRecordCopyValue + 14
5 Holler 0x00018df5 Holler + 97781
6 Holler 0x000182d3 Holler + 94931
7 Holler 0x0000a561 Holler + 38241
8 Holler 0x00033e0f Holler + 208399
9 CoreFoundation 0x3675d571 -[NSObject(NSObject) performSelector:withObject:withObject:] + 24
10 UIKit 0x355efec9 -[UIApplication sendAction:to:from:forEvent:] + 84
11 UIKit 0x355efe69 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 32
12 UIKit 0x355efe3b -[UIControl sendAction:to:forEvent:] + 38
13 UIKit 0x355efb8d -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 356
14 UIKit 0x355f0423 -[UIControl touchesEnded:withEvent:] + 342
15 UIKit 0x355eebf5 -[UIWindow _sendTouchesForEvent:] + 368
16 UIKit 0x355ee56f -[UIWindow sendEvent:] + 262
17 UIKit 0x355d7313 -[UIApplication sendEvent:] + 298
18 UIKit 0x355d6c53 _UIApplicationHandleEvent + 5090
19 GraphicsServices 0x35f11e77 PurpleEventCallback + 666
20 CoreFoundation 0x367c4a97 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 26
21 CoreFoundation 0x367c683f __CFRunLoopDoSource1 + 166
22 CoreFoundation 0x367c760d __CFRunLoopRun + 520
23 CoreFoundation 0x36757ec3 CFRunLoopRunSpecific + 230
24 CoreFoundation 0x36757dcb CFRunLoopRunInMode + 58
25 GraphicsServices 0x35f1141f GSEventRunModal + 114
26 GraphicsServices 0x35f114cb GSEventRun + 62
27 UIKit 0x35601d69 -[UIApplication _run] + 404
28 UIKit 0x355ff807 UIApplicationMain + 670
29 Holler 0x00002d79 Holler + 7545
30 Holler 0x00002d44 Holler + 7492
Unfortunately the last 8 items in the stack trace don't appear to be symbolicated. Is there a way for me to do this? I'm assuming hte problem is related to ABRecordCopyValue however I'm not 100% certain. Since I don't know what the last two Holler calls are, I'm somewhat confused. Anybody have an idea about what I should do to narrow down the problem?
I believe the problem now resides within a specific method as the sequence of events (ABRecordCopyValue) followed by two Holler calls is repeated. Here's the code ... I'm using it to load up a user's phone book/contact list. Let me know if this provides any more details:
ContactLists *list = [ContactLists defaultLists];
//Delete the phone contacts, and load them
[list clearContacts];
//Load them
ABAddressBookRef addressbook = ABAddressBookCreate();
if( addressbook )
{
//Got this via http://stackoverflow.com/questions/4641229/code-example-for-abaddressbookcopyarrayofallpeopleinsourcewithsortordering
ABRecordRef source = ABAddressBookCopyDefaultSource(addressbook);
CFArrayRef sortedPeople = ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressbook, source, kABPersonSortByFirstName);
//Sort them first
if( sortedPeople )
{
CFIndex contactCount = ABAddressBookGetPersonCount(addressbook);
for( int i = 0; i<contactCount; i++ )
{
ABRecordRef ref = CFArrayGetValueAtIndex(sortedPeople, i);
NSMutableString *fName = [[[NSMutableString alloc] init] autorelease];
NSMutableString *lName = [[[NSMutableString alloc] init] autorelease];
NSMutableDictionary *identifiers = [[[NSMutableDictionary alloc]init]autorelease];
if( ref )
{
//Get the user's name first
CFStringRef firstName = ABRecordCopyValue(ref, kABPersonFirstNameProperty);
if( firstName )
{
NSString *fn = [NSString stringWithFormat:#"%#",firstName];
if([fn hasPrefix:#"(null"])
[fName appendString:#""];
else
{
[fName appendString:[NSString stringWithFormat:#"%#", firstName]];
[fName setString:[fName stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[fName substringToIndex:1]uppercaseString]]];
}
CFRelease(firstName);
}
CFStringRef lastName = ABRecordCopyValue(ref, kABPersonLastNameProperty);
if( lastName )
{
NSString *ln = [NSString stringWithFormat:#"%#",lastName];
if([ln hasPrefix:#"(null"])
[lName appendString:#""];
else
[lName appendString:[NSString stringWithFormat:#"%#",lastName]];
CFRelease(lastName);
}
//If there is no first name don't deal with adding this contact to the ContactsList
if( [fName isEqualToString:#""] )
{
continue;
}
//Handle phone and email contacts
ABMultiValueRef phoneRef = ABRecordCopyValue(ref, kABPersonPhoneProperty);
if(phoneRef)
{
for( int i = 0; i<ABMultiValueGetCount(phoneRef); i++ )
{
CFStringRef phone = ABMultiValueCopyValueAtIndex(phoneRef, i);
if (phone) {
//Create the contact and add them to the phone contactList
NSString *mobileLabel = (NSString *)ABMultiValueCopyLabelAtIndex(phoneRef, i);
if( [mobileLabel isEqualToString:(NSString *)kABPersonPhoneMobileLabel] )
[identifiers setValue:(NSString *)phone forKey:#"Mobile:"];
if( [mobileLabel isEqualToString:(NSString *)kABPersonPhoneIPhoneLabel] )
[identifiers setValue:(NSString *)phone forKey:#"iPhone:"];
if( [mobileLabel isEqualToString:(NSString *)kABPersonPhoneMainLabel] )
[identifiers setValue:(NSString *)phone forKey:#"Main:"];
if( [mobileLabel isEqualToString:(NSString *)kABWorkLabel] )
[identifiers setValue:(NSString *)phone forKey:#"Work:"];
if( [mobileLabel isEqualToString:(NSString *)kABHomeLabel] )
[identifiers setValue:(NSString *)phone forKey:#"Home:"];
if( [mobileLabel isEqualToString:(NSString *)kABOtherLabel] )
[identifiers setValue:(NSString *)phone forKey:#"Other:"];
CFRelease(phone);
[mobileLabel release];
}
}
CFRelease(phoneRef);
}
ABMultiValueRef emailRef = ABRecordCopyValue(ref, kABPersonEmailProperty);
if (emailRef) {
if (ABMultiValueGetCount(emailRef) > 0) {
CFStringRef email = ABMultiValueCopyValueAtIndex(emailRef, 0);
if (email) {
[identifiers setValue:(NSString *)email forKey:#"Email:"];
CFRelease(email);
}
}
CFRelease(emailRef);
}
if( [identifiers count] > 0 )
{
//This is where I believe the problem is happen as it's two calls to internal Holler models
[list addContact:[[[Contact alloc]initWithIdentifiers:identifiers firstName:fName lastName:lName]autorelease]];
}
}
}
CFRelease(sortedPeople);
}
CFRelease(addressbook);
CFRelease(source);
}
You need to have the stack trace symbolicated before anything educated can be said about where the crash is.
If you open the stack trace file in Xcode (Import button in the Organizer window) it will automatically be symbolicated with the matching binary and symbolic file....
that is if you have saved the binary/symbolic files - preferably by using the archive function.
If you have not saved symbolic files for that exact file then you can not symbolicate the crash log and would have to wildly guess the real cause.
You really need to symbolicate the Holler methods in the stack trace. Here's how:
Go to TestFlight --> Select the Builds tab, then click the Testers button under the build that you are having issues with. Scroll down to the bottom and click on the bit.ly link that can be used to manually notify testers. At the bottom of that page, it gives you the option to download the .ipa file that you previously uploaded. Download it.
Once downloaded to your computer, rename the file extension from .ipa to .zip. Then unarchive it, and you should get the .app file. Since you only have the stack trace and not the full crash report, you can't use XCode to symbolicate, but you can do symbolication manually using the instructions found here: http://www.bartlettpublishing.com/site/bartpub/blog/3/entry/311
Hope that helps, and I'd love to be a beta tester for your future apps!

How to extend NSTextStorage?

According to documentation, I try to subclass NSTextStorage and use it in text view:
/*
NSTextStorage is a semi-abstract subclass of NSMutableAttributedString. It
implements change management (beginEditing/endEditing), verification of
attributes, delegate handling, and layout management notification. The one
aspect it does not implement is the actual attributed string storage --- this is
left up to the subclassers, which need to override the two
NSMutableAttributedString primitives:
- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str;
- (void)setAttributes:(NSDictionary *)attrs range:(NSRange)range;
*/
So I try to use delegate, to handle all needed events with same functionality:
#implementation MyTextStorage
- (id) init {
self = [super init];
if (self != nil) {
storage = [[NSMutableAttributedString alloc] init];
}
return self;
}
- (void) dealloc {
[storage release];
[super dealloc];
}
- (NSString *) string {
return [storage string];
}
- (void) replaceCharactersInRange:(NSRange)range withString:(NSString *)str {
[storage replaceCharactersInRange:range withString:str];
}
- (void)setAttributes:(NSDictionary *)attrs range:(NSRange)range {
[storage setAttributes:attrs range:range];
}
#end
It is no matter what I'm use as delegate: NSTextStorage or NSMutableAttributedString, The result is the same:
An uncaught exception was raised
* NSRunStorage, _NSBlockNumberForIndex(): index (18446744073709551615) beyond array
bounds (0)
* Terminating app due to uncaught exception 'NSRangeException', reason:
'*** NSRunStorage,
_NSBlockNumberForIndex(): index (18446744073709551615) beyond array
bounds (0)'
Stack trace:
0 CoreFoundation 0x00007fff840cd7b4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x00007fff885390f3 objc_exception_throw + 45
2 CoreFoundation 0x00007fff840cd5d7 +[NSException raise:format:arguments:] + 103
3 CoreFoundation 0x00007fff840cd564 +[NSException raise:format:] + 148
4 AppKit 0x00007fff86cc6288 _NSBlockNumberForIndex + 86
5 AppKit 0x00007fff86cc71d5 -[NSLayoutManager textContainerForGlyphAtIndex:effectiveRange:] + 364
6 AppKit 0x00007fff86d1f121 -[NSTextView(NSSharing) didChangeText] + 340
7 AppKit 0x00007fff86d44b68 -[NSTextView insertText:replacementRange:] + 2763
8 CocoaCalculator 0x0000000100002312 -[CalcTextView insertText:] + 65
9 CocoaCalculator 0x00000001000027ac -[CalcTextContainer initWithFrame:] + 1176
10 AppKit 0x00007fff86c23d44 -[NSCustomView nibInstantiate] + 646
11 AppKit 0x00007fff86b7be17 -[NSIBObjectData instantiateObject:] + 259
12 AppKit 0x00007fff86b7b202 -[NSIBObjectData nibInstantiateWithOwner:topLevelObjects:] + 336
13 AppKit 0x00007fff86b7988d loadNib + 226
14 AppKit 0x00007fff86b78d9a +[NSBundle(NSNibLoading) _loadNibFile:nameTable:withZone:ownerBundle:]
Termination start when I try to call
[textView insertText:#"123"];
But in standard NSTextStorage version all works properly.
What I need to do to extend this class ?
In addition to the NSAttributedString primitive methods that need implemented, I believe you also need to make a call to edited:range:changeInLength: inside your overrides of replaceCharactersInRange:withString: and setAttributes:range: respectively.
Something like:
- (void) replaceCharactersInRange:(NSRange)range withString:(NSString *)str {
[storage replaceCharactersInRange:range withString:str];
[self edited:NSTextStorageEditedCharacters range:range changeInLength:[str length] - range.length];
}
- (void)setAttributes:(NSDictionary *)attrs range:(NSRange)range {
[storage setAttributes:attrs range:range];
[self edited:NSTextStorageEditedAttributes range:range changeInLength:0];
}
The NSTextStorage documentation is a little bit vague in this area. The comment you quote in your question, about only needing to override 2 of the NSMutableAttributedString primitives only means that you don't have to override the other NSMutableAttributedString primitives.
You still have to override the primitives for the NSAttributedString superclass. Which means you need to implement -attributesAtIndex:effectiveRange:, -length and -string. I notice you did include an implementation of -string, so the two remaining ought to do it.
If you add:
- (NSUInteger)length
{
return [storage length];
}
- (NSDictionary *)attributesAtIndex:(NSUInteger)location effectiveRange:(NSRangePointer)range
{
return [storage attributesAtIndex:location effectiveRange:range];
}
... then hopefully it will fix this problem.