Potential Memory Leak for ABRecordCopyValue - memory-leaks

I am building an app that requres me to load all the contacts in the datasource of the table from the iPhone AddressBook. On running
Build and Analyze
for the following snippet
ABAddressBookRef addressBook = ABAddressBookCreate();
int nPeople = ABAddressBookGetPersonCount(addressBook);
CFRelease(addressBook);
for(int i=0; i < nPeople; i++ ){
//ABRecordRef person = [allPeople objectAtIndex:i];
NSString *name = #"";
if(ABRecordCopyValue([allPeople objectAtIndex:i], kABPersonFirstNameProperty) != NULL)
name = [[NSString stringWithFormat:#"%#", ABRecordCopyValue([allPeople objectAtIndex:i], kABPersonFirstNameProperty)] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
[dataSource addObject: name];
}
[allPeople release];
I am getting a potential memory leak for the line
name = [[NSString stringWithFormat:#"%#", ABRecordCopyValue([allPeople objectAtIndex:i], kABPersonFirstNameProperty)] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
I am really tired of fixing it but was unable to. Kindly help me out.
Any kind of help would be highly appriciated.
Thanks in advance!!

You aren't releasing the result of ABRecordCopyValue; try assigning it to a variable and release it and the end of the loop. Using a variable will also make your code a lot easier to read and highlight the cause of these issues better.
BTW, you are also calling ABRecordCopyValue twice with the same arguments, you should only do it once (using a variable as mentioned above).

I think you can do like below:
CFTypeRef copiedValue = ABRecordCopyValue([allPeople objectAtIndex:i], kABPersonFirstNameProperty);
name = [[NSString stringWithFormat:#"%#", copiedValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
CFRelease(copiedValue);

You can directly bridge to an NSString. It may be a little more clear:
CFTypeRef fn_typeref = ABRecordCopyValue(person, kABPersonFirstNameProperty);
CFTypeRef ln_typeref = ABRecordCopyValue(person, kABPersonLastNameProperty);
NSString * firstName = (__bridge NSString *) fn_typeref;
NSString * lastName = (__bridge NSString *) ln_typeref;
NSLog(#"Name:%# %#", firstName, lastName);
CFRelease(fn_typeref); // releasing CFTypeRef
CFRelease(ln_typeref);
// use firstName and lastName down here
NSLog(#"Name:%# %#", firstName, lastName);

Related

Saving contents of NSMutableArray containing custom class objects

I have a custom class "Bookmark" which contains an NSString. I use a NSMutableArray to store instances of this class thus making a bookmark list which I display in a UITableView with a UITableViewCell prototype.
Would someone please give some advice/example on how to save the instances within the NSMutableArray to a file (and perhaps an example how to load them). I can't get any examples I've searched to work. I've tried converting the array to NSData and using NSKeyedArchiver without success. I've also tried converting to an NSArray but can't get it to work.
Within the custom class I've implemented encodeWithCode and initWithCoder.
I need to save before the app closes and I want to load the list when the app is started.
I'm stuck... :(
EDIT: At the request of Ageektrapped, here are the code snippets:
Inside the implementation of my Bookmark class:
- (void) encodeWithCoder: (NSCoder *) encoder
{
[encoder encodeObject:self.address forKey:#"Address"];
}
- (id) initWithCoder: (NSCoder *) decoder
{
self = [super init];
if (self != nil)
{
self.address = [decoder decodeObjectForKey: #"Address"];
}
return self;
}
In my MasterViewController
self.bookmarks is a NSMutableArray containing bookmark objects. (When the code below is called, there is at least one entry in the bookmarks array.)
NSString *docFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory,NSUserDomainMask,YES) lastObject];
NSString *filename = [docFolder stringByAppendingPathComponent:#"data.plist"];
NSLog(#"File : %#", filename);
NSLog(#"Bookmarks : %d", self.bookmarks.count);
NSData *data = [NSKeyedArchiver archivedDataWithRootObject: self.bookmarks ];
if ([data writeToFile: filename atomically: YES])
{
NSLog(#"Successful write");
} else {
NSLog(#"Failed write");
}
I finally figured out what my problem was.
Because I'm debugging on my iPhone device, some folders are not writable. The code I was using was asking for a location in such an area (NSDocumentationDirectory):
After finally finding =>
How can I get a writable path on the iPhone? I understood my problem and got it working.
What I needed to do was replace:
NSString *docFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory,NSUserDomainMask,YES) lastObject];
NSString *filename = [docFolder stringByAppendingPathComponent:#"data.plist"];
with:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask,YES);
NSString *libFolder = [paths objectAtIndex: 0];
NSString *filename = [libFolder stringByAppendingPathComponent: #"data.archive"];
I also changed these lines (to be consistent with the example) from:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject: self.bookmarks ];
if ([data writeToFile: filename atomically: YES])
{
NSLog(#"Successful write");
} else {
NSLog(#"Failed write");
}
to:
BOOL success = [NSKeyedArchiver archiveRootObject: self.bookmarks toFile: filename];
if (success)
{
NSLog(#"Successful write");
} else {
NSLog(#"Failed write");
}
.
The code to read the file into the NSMutableArray on application startup is:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask,YES);
NSString *libFolder = [paths objectAtIndex: 0];
NSString *filename = [libFolder stringByAppendingPathComponent: #"data.archive"];
self.bookmarks = [NSKeyedUnarchiver unarchiveObjectWithFile: filename];

Core Data read only managed objects on thread not returning result to delegate

I need to use some core data managed objects in an NSOperation. The problem is that core data is not thread safe and apparently the object can't be loaded from the new thread. Does anybody know a good tutorial for this? I need the object read only... so the thread will not modify them in any way. Some other, unrelated entities may be added on the main thread while these objects are used in the background, but the background entities don't need to be modified at all..
Hmm seemed I fixed the background running issue, but now the problem is nothing is returned to the delegate... Why? In the thred if I nslog the results are all shown but that call to the delegate never happens
This is the code:
-(void)evaluateFormula:(Formula *)frm runNo:(NSUInteger)runCount{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue setMaxConcurrentOperationCount:2];
NSManagedObjectID *formulaId = frm.objectID;
for (int i = 0; i < runCount; i++) {
NSInvocationOperation * op = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(runFormula:) object:formulaId];
[queue addOperation:op];
}
}
-(void)runFormula:(NSManagedObjectID *)fId {
NSManagedObjectContext *thredContext =[[NSManagedObjectContext alloc] init];
NSPersistentStoreCoordinator *coord = (NSPersistentStoreCoordinator *)[(PSAppDelegate *)[[UIApplication sharedApplication] delegate] persistentStoreCoordinator];
[thredContext setPersistentStoreCoordinator:coord];
Formula *f = (Formula *)[thredContext objectWithID:fId];
NSDictionary *vars = [self evaluateVariables:[f.hasVariables allObjects]];
NSMutableString *formula = [NSMutableString stringWithString:f.formula];
for (NSString *var in [vars allKeys]) {
NSNumber *value =[vars objectForKey:var];
[formula replaceOccurrencesOfString:var withString:[value stringValue] options:NSCaseInsensitiveSearch range:NSMakeRange(0, [formula length])];
}
//parse formula
NSNumber *result = [formula numberByEvaluatingString];
// NSLog(#" formula %# result : %d",formula,[result intValue]);
//aggregate results
[self performSelectorOnMainThread:#selector(aggregate:) withObject:result waitUntilDone:YES]; // the delegate doesn't get called ...
}
-(void)aggregate:(NSNumber *)res {
[self.delegate didReceiveResult:res];
}

Core Data Problems with saving changes in NSManagedObjectContext

I am experiencing problems with how I handle my Core Data NSManagedObjectContext.
I can create NSManagedObject in my NSManagedObjectContext, but I failed to save the value.
Here's what I got:
_lesson.title = _titleField.text;
int priority = [_priorityField.text intValue];
int difficulty = [_difficultyField.text intValue];
int time = [_timeField.text intValue];
int sortIndex = 0;
if ( time == 0 )
{
sortIndex = 101;
}
else
{
sortIndex = priority * ( difficulty / time );
}
_lesson.priority = [NSNumber numberWithInt:priority];
_lesson.difficulty = [NSNumber numberWithInt:difficulty];
_lesson.time = [NSNumber numberWithInt:time];
_lesson.sortIndex = [NSNumber numberWithInt:sortIndex];
NSError* error = nil;
[[(AppDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext] save:&error];
Everything before the saving is working perfectly, I used NSLog to verify if each value is really saved in _lesson.
And _lesson is sent from here:
if ( [[segue identifier] isEqualToString:#"addLesson"] )
{
LessonViewController* destination = [[LessonViewController alloc]init];
Lesson* lesson = (Lesson*)[NSEntityDescription insertNewObjectForEntityForName:#"Lesson" inManagedObjectContext:_managedObjectContext];
destination.lesson = lesson;
}
else if ( [[segue identifier] isEqualToString:#"editLesson"] )
{
LessonViewController* destination = [[LessonViewController alloc]init];
NSIndexPath* index = [_tableView indexPathForCell:(UITableViewCell*)sender];
[_managedObjectContext deleteObject:[_lessonArray objectAtIndex:index.row]];
Lesson* lesson = (Lesson*)[_lessonArray objectAtIndex:index.row];
destination.lesson = lesson;
}
After debugging for two hours, I cannot find my error. Please help!
I will include my full code below:
https://www.dropbox.com/sh/eu62ie9svbbqdmm/u1hYUICfjy
That is my full source code. (I copied and pasted and created a mess. So, Dropbox!)
Thanks in advance.
This line looks suspicious:
[_managedObjectContext deleteObject:[_lessonArray objectAtIndex:index.row]];
You delete the Lesson object before passing it to the LessonViewController, so that saving the context will delete that object from the store, and not save a (modified) object, as you probably intended.
It seems to me that you should just delete that line in your code.
ADDED: There is an error in your prepareForSegue method: You create a new view controller with
LessonViewController* destination = [[LessonViewController alloc]init];
Instead, you must use the destination view controller of the seque:
LessonViewController *destination = [segue destinationViewController];

Export CoreData objects into NSDictionary or NS Array

I have a Core Data Object Which is Composed of Different Types NSString, Float,NSDATA,....
<Shoplog: 0x9c78d20> (entity: Shoplog; id: 0x9c77050 <x-coredata://828289C5-E1B8-48A6-B2A0-F68B7DF21F2E/Shoplog/p5> ; data: {
categoryname = Ines;
comments = nil;
date = nil;
email = "iloveyou#gmail.com";
image = <ffd8ffe0 00104a46 49460001 01000001 00010000 ffe10058 45786966 00004d4d 002a0000 00080002 01120003 00000001 0001>;
phone = 800;
price = 9988;
shop = "";
websiteurl = "http://www.google.com";
})
The issue is i want to Export this NSManaged Object into an NSArray or NSDictionary in order to write it to a file , in order to send it by mail to another User , & Open it from His App.
So Whenever i am Trying to use this Code
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"Shoplog.slog"];
[savedData writeToFile:filePath atomically:YES];
It Gives me a very small File 135bytes no matter how big is the Selected NSManagedObject i get the same Size .
i need help to understand what is going on wrong ?
I think about 1 Solutions :
1- Transfer the NsManagedObject to NSMutableArray using KVC Method
Although i still Believe there is a smarter Solution for this Problem , so if someone can help i will be Grateful.
Thank you
I have my Answer in the Following Link , It is Very Easy to Implement, Just follow the Steps
Serializing (Archiving/Unarchiving) an NSManagedObject Graph

Storing UIActionSheet data into array in CoreData

I've got an issue that's been bothering me. I have to store information from a UI Action Sheet in iOS into an array provided in CoreData. Trouble is, the Action Sheet is in a different function than the one used to store the data.
First: Here's the relevant code for storing the data:
(... checking for all fields; working properly)
}
else
{
newContact = [NSEntityDescription insertNewObjectForEntityForName:#"Contacts" inManagedObjectContext:context];
[newContact setValue:Salutation.text forKey:#"Salutation"];
[newContact setValue:FirstName.text forKey:#"FirstName"];
[newContact setValue:LastName.text forKey:#"LastName"];
[newContact setValue:CompanyName.text forKey:#"CompanyName"];
[newContact setValue:EmailAddress.text forKey:#"EmailAddress"];
[newContact setValue:PhoneNumber.text forKey:#"PhoneNumber"];
newContact.Disinfector =[NSNumber numberWithBool:yesWasher];
newContact.Sterilizer =[NSNumber numberWithBool:yesSterilizer];
newContact.CoffeeMaker =[NSNumber numberWithBool:yesCoffeeMaker];
Salutation.text = #"";
FirstName.text = #"";
LastName.text = #"";
CompanyName.text = #"";
EmailAddress.text = #"";
PhoneNumber.text = #"";
yesWasher = YES;
[WasherTog setImage:[UIImage imageNamed:#"checked.png"] forState:UIControlStateNormal];
yesSterilizer = YES;
[SterilizerTog setImage:[UIImage imageNamed:#"checked.png"] forState:UIControlStateNormal];
yesCoffeeMaker = YES;
[CoffeeMakerTog setImage:[UIImage imageNamed:#"checked.png"] forState:UIControlStateNormal];
Second, here's the code for the Action Sheet and handling the input:
- (void)showSalutation:(id)sender
{
UIActionSheet *popUp = [[UIActionSheet alloc] initWithTitle:#"Choose Salutation" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:#"Cancel" otherButtonTitles:#"Mr.", #"Mrs.", #"Ms.", #"Dr.", nil];
popUp.actionSheetStyle = UIActionSheetStyleBlackTranslucent;
[popUp showInView:self.view];
[popUp release];
}
- (void)showSalutation:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0)
{
Salutation.text = #"Mr.";
}
else if (buttonIndex == 1)
{
Salutation.text = #"Mrs.";
}
else if (buttonIndex == 2)
{
Salutation.text = #"Ms.";
}
else if (buttonIndex == 3)
{
Salutation.text = #"Dr.";
}
}
I feel like I'm making a lot of newbie mistakes, so please forgive me. I've been learning how to code all weekend and you guys have been my best friend for this stuff. I just haven't seen this particular issue on the net.
Thanks in advance for your help!
Chris
If you are jsut trying to select a string based on the button index use an instance variable. For example you could declare NSString* yourString in the header and use it as follows:
if (button.index == 0) {
yourString = #"Mr."
}
Just following that pattern should work and you can do whatever you want with yourString from there.

Resources