NSXMLParserDelegate memory issues - ios

I'm running my app through Instruments, and every time the following setup causes a memory leak (apparently). I can't see an issue with this.
WeatherParser.h:
...
{
NSMutableDictionary *results;
}
#property (nonatomic, retain) NSMutableDictionary *results;
WeatherParser.m
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
self.results = [[NSMutableDictionary alloc] init];
}
...add values to results
- (void)dealloc
{
self.results = nil;
[self.results release];
[super dealloc];
}
Would greatly appreciate any observations.

Swap these around to read:
[self.results release];
self.results = nil;
you were calling the release on the nil object not on the results array.

Related

Weak properties & prepareForSegue: one property becomes null and the other one not [duplicate]

Why temp object is not released and set to nil even though it is declared as __week. But in case of Person object its working as expected. Do NSString objects memory life cycle is handled differently? How?
#interface Person : NSObject
#property(nonatomic, strong) NSString *name;
- (instancetype)initWithName:(NSString *)name;
+ (Person *)personWithName:(NSString *)name;
#end
#implementation Person
- (instancetype)initWithName:(NSString *)name {
if (self = [super init]) {
self.name = name;
}
return self;
}
+ (Person *)personWithName:(NSString *)name {
return [[self alloc] initWithName: name];
}
#end
- (void)viewDidLoad {
__weak NSString *temp;
#autoreleasepool {
NSMutableArray *data = [[NSMutableArray alloc] initWithObjects:#"firstString", #"secondString", nil];
temp = data[0];
[data removeObjectAtIndex:0];
}
NSLog(#"%#", temp);//prints firstString instead of null
__weak Person *person ;
#autoreleasepool {
NSMutableArray *persons = [[NSMutableArray alloc] initWithObjects:[Person personWithName:#"Steve"], [Person personWithName:#"Harry"], nil];
person = persons[0];
[persons removeObjectAtIndex:0];
}
NSLog(#"%#", person.name);//prints null as expected because person object will be deallocated,
}
Constant strings are never released. There are other objects that are never released, like certain NSNumber objects (on 64 bit versions, most NSNumber objects).
It makes me wonder what you are up to. What do you want to do if that NSString* becomes nil (which it won't)?

Using the copy attribute causes a segmentation fault

I have started a Master Detail application and left the generated code untouched. I created and added two additional classes: a book class(contains an NSString for a title, author, and summary) and also a data controller class(contains a mutable array to store the books).
My understanding of #property attributes after reading Apple doc and others is this:
strong - default, creates ownership of an object
weak - alternative to strong, used to avoid retain cycles
copy - creates a copy of the existing object and takes ownership of that
nonatomic - disregards any sort of thread safety
This code throws a segmentation fault in addBookToList when the #property AJKBook is declared with the copy attribute and I don't understand why.
#interface AJKBookDataController ()
// when current book uses the copy attribute code seg faults in addBookToList
#property (nonatomic) AJKBook *currentBook;
#property (nonatomic, copy) NSString *currentValue;
- (void)populateBookList;
- (void)addBookToBookList;
#end
#implementation AJKBookDataController
- (id)init
{
self = [super init];
if (self) {
_bookList = [[NSMutableArray alloc] init];
_currentBook = [[AJKBook alloc] init];
_currentValue = [[NSString alloc] init];
[self populateBookList];
return self;
}
return nil;
}
- (void)setBookList:(NSMutableArray *)bookList
{
// this bit of code ensures bookList stays mutable
if (_bookList != bookList) {
_bookList = [bookList mutableCopy];
}
}
- (void)populateBookList
{
NSURL *url = [NSURL URLWithString:#"https://sites.google.com/site/iphonesdktutorials/xml/Books.xml"];
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[parser setDelegate:self];
[parser parse];
NSLog(#"%#", [self.bookList description]);
}
- (void)addBookToBookList
{
[self.bookList addObject:self.currentBook];
self.currentBook = [[AJKBook alloc] init];
}
...
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"title"]) {
// [self.currentBook title:self.currentValue];
self.currentBook.title = self.currentValue;
} else if ([elementName isEqualToString:#"author"]) {
self.currentBook.author = self.currentValue;
} else if ([elementName isEqualToString:#"summary"]) {
self.currentBook.summary = self.currentValue;
} else if ([elementName isEqualToString:#"Book"]) {
[self addBookToBookList];
}
self.currentValue = [NSString stringWithFormat:#""];
}
#end
if you want to use copy for your custom classes you have to implement – copyWithZone: in those classes.
But you don't have to use copy. Often strong is good enough. copy is mostly used for NSString properties because you want to prevent that a NSMutableString is assigned and later changed from outside the class.
You have to think if you really need to copy the current book. If something is named current in my opinion that's a strong indication that you do NOT want to copy. If the only assignment is from [[AJKBook alloc] init]; copy does not make sense at all.

Accessing arrays in another instance of a class objective c

I have a #property (nonatomic,retain) NSMutableArray *transfer_array; in .h file and in my .m I have
#synthesize transfer_array = _transfer_array;
- (id)init
{
self = [super init];
if(self) {
self.transfer_array = [[NSMutableArray alloc] init];
}
return self;
}
and I add objects to the array in this function
- (id)display:(double)imageXX andY:(double)imageYY withName:(NSString *)namee{
//if((self == [super init])){
NSLog(#"````````````````````````````````````````````````````````");
NSLog(#"imageX: %f",imageXX);
NSLog(#"imageY: %f", imageYY);
NSLog(#"name: %#", namee);
labelPoi = [[Poi alloc] init];
labelPoi.imageLocationX = imageXX;
labelPoi.imageLocationY = imageYY;
labelPoi.name = namee;
[self.transfer_array addObject:labelPoi];
The objects add successfully bu whenever I try to access the array elements in another instance such as:
- (void)viewDidLoad{
[super viewDidLoad];
NSLog(#"transfer_array count: %lu",(unsigned long)self.transfer_array.count);
Then the array is empty.
Any help would be appreciated!
Instances are independent objects. Changing the internal state of one doesn't affect the internal state of others.

Can't restore archived data

Ok, I've been over this a million times in the last week and I just am not getting it. (And yes, I've read Apple's docs.)
I am archiving my object and it appears to be archiving correctly (I can see the file written to the file system and if I examine it I can see my data within). However, when I relaunch my app my data is not being restored. Every example I read tells me how easy this is but I'm just not getting it. One unique thing is that my object is a singleton, it's used for passing data between view controllers.
I'd really appreciate some sage advice. Thanks in advance.
Here's my header:
#import <Foundation/Foundation.h>
#interface SharedAppDataObject : NSObject <NSCoding>
{
NSMutableDictionary *apiKeyDictionary;
NSString *skuFieldText;
NSIndexPath *checkmarkIndex;
}
+ (SharedAppDataObject *)sharedStore;
#property (nonatomic, copy) NSString *skuFieldText;
#property (nonatomic, copy) NSIndexPath *checkmarkIndex;
#property (nonatomic, copy) NSMutableDictionary *apiKeyDictionary;
-(void)setValue:(NSString *)apiKey forKey:(NSString *)name;
-(void)setSkuField:(NSString *)s;
-(void)setCheckmarkIndex:(NSIndexPath *)p;
-(NSMutableDictionary *)apiKeyDictionary;
-(BOOL)saveChanges;
#end
Here's my implementation:
#import "SharedAppDataObject.h"
#implementation SharedAppDataObject
#synthesize skuFieldText;
#synthesize checkmarkIndex;
#synthesize apiKeyDictionary;
//create our shared singleton store
+(SharedAppDataObject *)sharedStore {
static SharedAppDataObject *sharedStore = nil;
if (!sharedStore) {
sharedStore = [NSKeyedUnarchiver unarchiveObjectWithFile:[SharedAppDataObject archivePath]];
if(!sharedStore)
sharedStore = [[super allocWithZone:NULL] init];
}
return sharedStore;
}
-(id) init {
self = [super init];
if (self) {
}
return self;
}
-(void)setValue:(id)apiKey forKey:(NSString *)name {
[apiKeyDictionary setObject:apiKey forKey:name];
}
-(void)setSkuField:(NSString *)s {
skuFieldText = s;
}
-(NSMutableDictionary *)apiKeyDictionary {
return apiKeyDictionary;
}
-(void)setCheckmarkIndex:(NSIndexPath *)p {
checkmarkIndex = p;
}
-(void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:skuFieldText forKey:#"skuFieldText"];
[aCoder encodeObject:checkmarkIndex forKey:#"checkmarkIndex"];
[aCoder encodeObject:apiKeyDictionary forKey:#"apiKeyDictionary"];
}
-(id)initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self) {
[self setSkuFieldText:[aDecoder decodeObjectForKey:#"skuFieldText"]];
[self setCheckmarkIndex:[aDecoder decodeObjectForKey:#"checkmarkIndex"]];
[self setApiKeyDictionary:[aDecoder decodeObjectForKey:#"apiKeyDictionary"]];
}
return self;
}
+(NSString *)archivePath {
NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [documentDirectories objectAtIndex:0];
return [documentDirectory stringByAppendingPathComponent:#"bbyo.archive"];
}
-(BOOL)saveChanges {
return [NSKeyedArchiver archiveRootObject:self toFile:[SharedAppDataObject archivePath]];
}
#end
Save method from App Delegate:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
BOOL success = [[SharedAppDataObject sharedStore] saveChanges];
if (success) {
NSLog(#"Saved all the data");
} else {
NSLog(#"Didn't save any of the data");
}
}
Initialize sharedStore = [NSKeyedUnarchiver unarchiveObjectWithFile:[SharedAppDataObject archivePath]]; in application:didFinishLaunchingWithOptions:. This method is used to initialize data structures and restore previous app state.
Also, take out static SharedAppDataObject *sharedStore = nil; from sharedStore. If the save file exists, [ShareAppDataObject sharedStore] will always unarchive the file which is not necessary. It can be unarchived once during initialization.
Here's a post that can answer your problem: http://bit.ly/PJO8fM
I cannot give you the answer but some ideas to figure this out. Taking this line:
sharedStore = [NSKeyedUnarchiver unarchiveObjectWithFile:[SharedAppDataObject archivePath]];
So if the sharedStore is nil, something is wrong - so test for it. If nothing then log the path, and use NSFileManager methods to see if the file is there, its size etc. If you find the file is there and has size, but you cannot unarchive it, that's a problem of course. In that case, add special debug code just after you create the file:
-(BOOL)saveChanges {
BOO ret = [NSKeyedArchiver archiveRootObject:self toFile:[SharedAppDataObject archivePath]];
id foo = [NSKeyedUnarchiver unarchiveObjectWithFile:[SharedAppDataObject archivePath]];
// check if foo is not nil, if its the proper class, etc.
}
If when you save the file you can unarchive it just fine, but cannot on restart of the app, then something is wrong with the file. All this info should point the way to a solution.
Another thought - when you encode the data, log it, just to be sure its not nil - but even if so the unarchive should work.

Which one is the right method of initializing a NSMutableDictionary . Please anyone correct me here

I am trying to create a NSMutableDictionary in my class. I have read many post in stackoverflow to understand the difference. But now i am totally confused. So any one correct me , which one is the correct way of initialing a NSMutableDictionary in my class . I have to access this dictiionary in many areas of my application .So suggest me the good way of using the variable initialization ...
/// .h file
#interface ActiveFeeds : NSObject {
}
#property (nonatomic, copy) NSMutableDictionary *invDictionary;
#property (nonatomic, retain) NSString *filePath;
#end
#implementation ActiveFeeds
#synthesize filePath;
#synthesize invDictionary;
- (id)init{
self = [super init];
if (self != nil){
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:self.filePath];
self.invDictionary = [dictionary mutableCopy];
dictionary release];
}
return self;
}
/* And use self.invDictionary all in the application */
- (void)setObjectAtKey:(NSMutableDictionary *)objectDic atKey:(NSString *)setKey{
[self.invDictionary setObject:objectDic forKey:setKey];
}
- (void)dealloc {
[self.invDictionary release];
[self.filePath release];
[super dealloc];
}
#end
or like this ....
#interface ActiveFeeds : NSObject {
NSMutableDictionary *invDictionary;
NSString *filePath;
}
#end
#implementation ActiveFeeds
- (id)init{
self = [super init];
if (self != nil){
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
invDictionary = [dictionary mutableCopy];
[dictionary release];
}
}
return self;
}
/* And use invDictionary all in the application */
- (void)setObjectAtKey:(NSMutableDictionary *)objectDic atKey:(NSString *)setKey{
[invDictionary setObject:objectDic forKey:setKey];
}
- (void)dealloc {
[invDictionary release];
[filePath release];
[super dealloc];
}
#end
Please any one help me to get the correct way of using the variables ....
- (id)initWithFilePath:(NSString *)path{
self = [super init];
if (self != nil){
self.filePath = path;
self.invDictionary = [NSMutableDictionary dictionaryWithContentsOfFile:path];
}
return self;
}
also
- (void)dealloc {
[invDictionary release];
[filePath release];
[super dealloc];
}

Resources