I am battling with this piece of code for days now, I really would appreciate your insight. So here it is...
fileName which is declared in my .h file as
NSString *fileName;
and later as
#property (nonatomic, copy) NSString *fileName;
is not accessible inside viewWillDisappear. It just shows up as nil object, or some weird value when I debug. When I debug, my console show this msg:
Printing description of fileName:
FileNumber1
When I reach to viewWillDisappear my console shows this:
Printing description of fileName:
Yeah, just nothing for fileName.. the value simply disappears.. I just don't know why!!!
MORE DETAILS:
Inside my init method I do the following and it works fine.
fileName = [[NSString alloc] initWithString:(NSString *)CFURLGetString(pdfURL)];
fileName = [[fileName lastPathComponent] stringByDeletingPathExtension];
fileName = [fileName stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
Throughout the program I can access fileName just fine, but inside viewWillDisappear I am trying to save to my standardUserDefaults by attempting the following:
NSUserDefaults *ud = [[NSUserDefaults standardUserDefaults] autorelease];
NSArray *tmp = [NSArray arrayWithArray:someMutableArray];
[ud setObject:tmp forKey:fileName]; // THE PROBLEM IS HERE WITH fileName AS AKEY
[ud synchronize];
[tmp release];
At this point someMutableArray is accessible, but fileName is not. Any insight, thoughts, ideas, will be appreciated.
in your init method change it to read self.fileName =
You need to use your property methods so that a copy of the string will be made, currently because you are using the variable rather than the property you are assigning an autoreleased string. By using self.fileName the string will be copied and will not be autoreleased.
Related
I have used the following code.
MainView.h:
NSString *sCopySource;
NSString *sFileSource;
// retain and copy used both for test proposes
#property (nonatomic, retain) NSString *sCopySource;
#property (nonatomic, copy) NSString *sFileSource;
MainView.m:
// Inside the first method:
sCopySource = [NSString stringWithFormat:#"%#%#", path1, filename];
sFileSource = [NSString stringWithFormat:#"%#%#", path2, filename];
// Inside the second method:
[[NSFileManager defaultManager] copyItemAtPath:sCopySource toPath:sFileSource error:&err];
And take error in the last line of the code by zombie-enabled objects sCopySource and sFileSource:
message sent to deallocated instance
Why? The properties marked as retain and copy. How to fix this?
Thanks a lot for the help!
P.S. Please don't answer to use ratain and release methods. They're extremely inconvenient.
You have defined the property, but you are writing directly to the instance variable.
If you want to use the retain/release logic in the property, you need to use:
self.sCopySource = [NSString stringWithFormat:#"%#%#", path1, filename];
self.sFileSource = [NSString stringWithFormat:#"%#%#", path2, filename];
That way, the methods that do the copy and retain are used.
I am kind of new to iOS development.
I want to retrieve strings from the text(.rtf) file I have. The file is within my application main bundle. It's content are:
#start word1 First word end word2 Second word end //lots of things to be added later
Code:
path = [[NSBundle mainBundle]pathForResource:#"words" ofType:#"rtf"];
if(path)
{
NSLog(#"path exists");
}
NSError *error = nil;
NSString *file = [[NSString alloc]initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
if(error)
{
NSLog(#"error");
}
NSString *finalword= [[NSString alloc]init ];
NSString *startfrom = [[NSString alloc] initWithFormat:#"word%i",i+1];
i++;
NSLog(#"%#",startfrom);
NSString *wordoftheday = [[NSString alloc]init ];
NSScanner *scanner = [NSScanner scannerWithString:file];
[scanner scanUpToString:startfrom intoString:nil];
[scanner scanUpToString:#"end" intoString:&wordoftheday];
finalword = [wordoftheday substringFromIndex:[startfrom length]];
NSLog(#"%#",finalword);
Word.text = final word; //change label text
//[final word release];
//[wordoftheday release];
//[file release];
Code is working fine but it leaves me with memory management issues. App crashes if I release the variables in the last commented code.
Also this method is in my viewdidload. I want the label to change text when user click a button. I will have to write the same code again in that method which leaves me with more memory issue.
So looking at these one by one, focusing on the memory issues and not the overall strategy here:
NSString *finalword= [[NSString alloc]init ];
Here you alloc/init a new immutable and empty NSString, and then you end up overwriting the pointer to this later anyway. You should just delete this line. And then you'll need to move the declaration down a few lines to this:
NSString *finalword = [wordoftheday substringFromIndex:[startfrom length]];
Then you have:
NSString *startfrom = [[NSString alloc] initWithFormat:#"word%i",i+1];
This one you need to release later. Or just change it to:
NSString *startfrom = [NSString stringWithFormat:#"word%i",i+1];
Then you have:
NSString *wordoftheday = [[NSString alloc]init ];
Same story as finalword. Except that you do need to define this variable so you can pass it to the scanner later. So change it to:
NSString *wordoftheday = nil;
And lastly, you can release 'file'. That is fine. But you don't want to release 'wordoftheday' or 'finalword' because you don't own those strings. You did not create them yourself.
And one other note:
if(error)
That is not the correct way to check for an error in loading 'file'. You should check the return from the method and then look for an error if and only if the return value was nil. So change that line to:
if(!file)
(OK, that wasn't really a memory issue, but a bug I did notice.)
I think that's all of it at least as far as memory issues. I hope that helps.
make those variables as member variables and release in the dealloc
I'm having an issue with the memory management in my application. I have an NSDictionary instance variable that I'm setting equal to another NSDictionary that gets made in a method. This all works fine and my application behaves like I want it to, but I'm having trouble applying the proper memory management.
If I release the local dictionary it eventually causes a crash as the method is called repeatedly, because the data saved in the instance variable is also trashed. Here's the code:
NSBundle *bundle = [NSBundle mainBundle];
NSString *plistPath = [bundle pathForResource:#"Names" ofType:#"plist"];
NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
self.dictAllValues = dictionary;
[dictionary release];
Create dictAllValues using
#property(retain) NSDictionary *dictAllValues;
Your method
-(void) myMethod
{
NSBundle *bundle = [NSBundle mainBundle];
NSString *plistPath = [bundle pathForResource:#"Names" ofType:#"plist"];
NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
self.dictAllValues = dictionary;
[dictionary release];
}
and release in dealloc method
-(void) dealloc
{
[dictAllValues release];
[super dealloc];
}
How do you declare dictAllValues? Typically, it would be:
#property(retain) NSDictionary *dictAllValues;
If so, then the release in your code is correct and your problem lies elsewhere. Post the backtrace of the crash, use Build and Analyze and fix any issues, and try turning on Zombie detection.
From the apple memory management guide.
As a corollary of the fundamental rule, if you need to store a received object as a property in an instance variable, you must retain or copy it.
So, in this case putting [dictionary release]; in dealloc method instead (or any other method you might use for clean up) should work fine.
I assume your dictAllValues property uses simple assignment, let me know if that's not the case.
I'm implementing the following function on appdelegate,
but I need to write NSString type instead of typical float values.
Since xcode doesn't allow an object to be in my desired position,
I used char* instead as follows, where as my data to be passed are of type NSString.
As expected, it doesn't work...
How could I manipulate it so that I could write NSString data type?
Should I make some conversion?
Please help me out..
- (void)addHallOfFamer:(char*)newHofer{
[hofArray addObject:[NSString stringWithFormat:#"%#",newHofer]];
[hofArray sortUsingSelector:#selector(compare:)];
NSArray* paths =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
NSString* hofArrayPath = [documentsDirectory
stringByAppendingPathComponent:#"hofers.plist"];
[hofArray writeToFile:hofArrayPath atomically:YES];
}
(added)
following is how I'm calling the written NSStrings from another view, which doesn't reflect my updating.
MainAppDelegate* delegate;
delegate = (MainAppDelegate*)[[UIApplication sharedApplication] delegate];
NSArray *hofers = [[delegate.hofArray reverseObjectEnumerator] allObjects];
hoferName1.text = [NSString stringWithFormat:#"%#",[hofers objectAtIndex:0]];
First, with the current char * argument, you need to use %s as your format directive, not %#.
Second, to use an NSString * as your argument, just add it to hofArray.
The easiest solution would be to just save the array in NSUserDefaults. Since it is an array of strings, saving and retrieving it that way should work fine and would be easier than dealing with the iOS filesystem.
Edit:
If you really want to save it in the filesystem, look into the NSKeyedArchiver method + (BOOL)archiveRootObject:(id)rootObject toFile:(NSString *)path and the NSKeyedUnarchiver method + (id)unarchiveObjectWithFile:(NSString *)path.
Edit 2:
As ondmike pointed out, you need to use %s rather than %# for your -stringWithFormat: method call to work properly. Relevant documentation is String Format Specifiers
I seem to have a fundamental gap in my memory management understanding. The code below is located within a singleton that gets called multiple times within my app to parse data that is downloaded from the web. For each article I download, I allocate a mutable string, then do tons of parsing, then write the file to the file system for later display in a UIWebView.
But every time I enter this method, I allocate a new "articleString". And I never release this string. I think this is a leak, but if I add a release at the bottom of this method (after the file is written), my app crashes the next time this method is called. I don't understand why it crashes, since another NSMutableString is allocated next time it is called.
UPDATE: I do release articleString in the dealloc method. But it still seems that I should release at the end of this method, since I alloc every time I enter.
UPDATE: articleString is defined as follows in the header:
#property (nonatomic, retain) NSMutableString *articleString;
the parseArticle method below is a placeholder for a series of methods that manipulate articleString.
self.articleString = [[NSMutableString alloc] initWithData:articleData encoding:NSUTF8StringEncoding];
//Parse the article for display
[self parseArticle];
//Write the article string to a file for later display
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"article.html"];
NSLog(#"%#", articleString);
[articleString writeToFile:path atomically:YES];
I like to let properties handle this for me. If the articleString property is set to retain then this is simple.
self.articleString = [[[NSMutableString alloc] initWithData:articleData encoding:NSUTF8StringEncoding] autorelease];
[self doStuff];
Then
- (void)dealloc {
self.articleString = nil;
[super dealloc]
}
article string will get released and properly retain when you set a new one. And it will be cleaned up on dealloc.