I have a simple method run in background thread which open txt file and split it on lines. After that I'm trying to release memory, but something goes wrong. I'm using ARC. Here's code:
#autoreleasepool {
NSString* file = [NSString stringWithContentsOfFile:resourcePath encoding:NSWindowsCP1251StringEncoding error:&error];
NSArray* test = [file componentsSeparatedByString:#"\n"];
test = nil;
}
String released fine, but array still in memory. What I've missed?
UPD: Hm... Just tried to duplicate array few times, and after end of the method array really deallocates. But there is memory leak if I create this array. Where it could be?
// test = nil;
Dismiss it, and ARC will work fine.
Related
I have an NSDragOperation that gets a property lists path upon the user dragging it into the window. That seems to work just fine, and I can save the path information to an NSString:
NString *thisPath = draggedFilePath;
NSLog(#" %#",thisPath);
output: 2014-02-09 09:19:46.072 app[5944:303] /Users/Me/Desktop/file.plist
The problem starts when I go into a dispatch queue. When I try and read the NSString from inside the background queue the output becomes NSPrincipalClass. Does anyone know why this is happening, or if I'm supposed to convert the NSString to some other format before entering dispatch_queue_t?
dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(backgroundQueue, ^{
for (NSUInteger i = 0; i < 1; i++) {
dispatch_async(dispatch_get_main_queue(), ^{
});
}
NSLog(#" %#",thisPath);
output: 2014-02-09 09:19:56.234 app[5944:12203] NSPrincipalClass
EDIT: the output of the string using NSLog inside dispatch queue turns up random symbols, and also crashes. The last output was <__NSMallocBlock__: 0x55a860> - I have other strings that seem to be just fine within the same function, so I really don't know what is causing this.
one of three things is happening...
it is being deallocated, and a new object is being allocated in its place... you can try zombies...
it is getting assigned to a garbage value ie. draggedFilePath isn't ever initialized to zero, and isn't set to a good value.
your stack is getting smashed and it just happens to be there when it crashes... this is the hardest to find.
you are going to have to turn on zombies, the exception breakpoint and just step through it in the debugger... if that fails you get to either run in instruments with the malloc tool or turn on malloc history logging.
Does it work if you prefix the declaration of thisPath with `__block'? Like this:
__block NString *thisPath = draggedFilePath;
I'm trying to copy multiple files to the clipboard and I'm not sure what I'm missing. I wrote this little program just to test putting one file on the clipboard, but after it runs, there's nothing on the clipboard. I can't see what I'm missing. Here's the code I'm running:
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
NSInteger changeCount = [pasteboard clearContents];
NSMutableArray *filesToCopy;
NSString* pathToFile = #"/Users/user/Downloads/file1.jpg";
NSURL* fileURL = [[NSURL alloc] initFileURLWithPath:pathToFile];
[filesToCopy addObject:fileURL];
BOOL OK = [pasteboard writeObjects:filesToCopy];
Put a breakpoint on the line:
[filesToCopy addObject:fileURL];
When it is reached examine the variables involved, see the problem?
To convince yourself you are right step over the statement and then examine the variables again.
HTH
Actually, I feel silly now. The problem was that the array was never actually initialized. I'm surprised an exception wasn't thrown because addObject was done on a nil object. The line
NSMutableArray *filesToCopy;
should be
NSMutableArray *filesToCopy = [[NSMutableArray alloc] init];
Im downloading some gzipped xml files from a server, save it to the documents folder and unzip every file. After that I delete the .gz file. I do that in a loop for more or less 500 files. When im using instruments, I see that the live bytes more or less are 470MB after this process. When Im waiting some seconds, the ARC clears it and the application is going to 5mb live bytes. But because its a synchronization process my app gets a memory warning right after that when I dont stop after the downloading and unzipping. At least I think it should be possible to force the ARC to release the memory? Or do I have a real bad code and I am just still dont see that?
Any help or hint is really appreciated.
Downloading and unzipping:
for(NSString *filePath in filePaths){
NSString *localPath = [[DownloadManager sharedInstance] downloadFile:filePath];
if(localPath){
//downloaded correctly
if([self unzipFileAtPath:localPath]){
[FileUtility deleteFileAtPath:localPath];
}
}
}
Unzip method:
+ (BOOL)unzipFileAtPath:(NSString *)path
{
NSData *gzData = [NSData dataWithContentsOfFile:path];
NSData *ungzippedData = [gzData gunzippedData];
BOOL success = [ungzippedData writeToFile:[FormatUtility pathWithoutGz:path] atomically:NO];
ungzippedData = nil;
gzData = nil;
return success;
}
Wrap the inside of your for-loop with an autorelease pool:
for (NSString* filePath in filePaths) {
#autoreleasepool {
// do work
}
}
The problem actually has nothing to do with ARC. Methods like dataWithContentsOfFile: will return a new autoreleased object instance. These objects will not be released until the enclosing autorelease pool is drained, which by default only happens at the end of your thread/operation or when you return to the run-loop.
When you allocate many temporary objects in a loop, like you're doing, you should use your own autorelease pool to ensure that these temporary objects do not accumulate needlessly.
I am facing a similar problem when downloading a very large zip file (of 5GB!) using AFNetworking 2.6.4 and AFDownloadRequestOperation 2.0.1. I find the such memory issue is caused by the Flipboard FLEX 2.1.1 framework. After I commented out the line [[FLEXManager sharedManager] setNetworkDebuggingEnabled:YES]; it works perfectly fine.
I am downloading images from a url using NSDATA and saving them to local file system using
NSData *dataForStorage = [NSData dataWithData:UIImagePNGRepresentation(img)];
BOOL saveResult=[ dataForStorage writeToFile:jpegFilePath options:NSDataWritingAtomic error:&error];
NSLog(#"Write returned error: %#", [error localizedDescription]);
My app crashes randomly without even giving a message, though some files are saved (again randomly). When I run the app in Debug mode, I frequently see "EXC_BAD_ACCESS" but continuing execution succeeds in saving some of the files.
This code is executed in background from:
[self performSelectorInBackground:#selector(loadImageInBackground:) withObject:arr];
Please suggest.
One of the problems in your code is that your running code in a thread without an autorelease pool but are using functions that would require one. Put the following code into the loadImageInBackground method:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// existing code
[pool drain];
This is probably just one of several problems. For further assistance, we need to see the stack trace of the crash.
Just a wild guess : arr is an autoreleased object, so, sometimes it gets deallocated before your selector gets called. Try using [arr copy] and release it after saving it.
I was having the EXACT same problem, but it turned out that the problem was something else: my URL was getting release prematurely. In the end this is what I did and it worked:
I made this call:
[self performSelectorInBackground:#selector(downloadData:) withObject:nil];
And this is the method:
// URL - (NSString) URL for file
// filePath - (NSString) save location on device
-(void)download:(NSString *)URL
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:URL]];
[data writeToFile:filePath atomically:YES];
[pool release];
}
So I think that your download code is correct, but there is some other variable that is getting deallocated early (possibly your path).
Hope this helps! I know the other answers on this page worked for me.
I have been searching for many days on how to save my apps data. I found some stuff but it was very complicated and badly explained. I need that when I completely close my apps all the data I entered in the text field are still there when I open my apps again. I tried a tutorial but this only let me save about 8 textfields and I need to save thousands I am starting Objective-C and Xcode so if somebody want to give me an answer please make it very precise.
Alright, what I'd suggest would be putting all the data from your text fields into an array and saving that to a file, then loading it when you re-open the app.
The first thing you need is a save file. This function will create one for you.
-(NSString*) saveFilePath{
NSString* path = [NSString stringWithFormat:#"%#%#",
[[NSBundle mainBundle] resourcePath],
#"myfilename.plist"];
return path;}
Now that that's done you need to create your saving array. Hopefully you have your thousands of textfields already fitted into an array of some sort. If not, this will be a painful process regardless of how you tackle it. But anyway... (Here, labelArray will be the array of all your text fields/labels/etc.)
NSMutableArray* myArray = [[NSMutableArray alloc]init];
int i = 0;
while(i < labelArray.count){
[myArray addObject: [labelArray objectAtIndex: i].text];
i ++;
}
[myArray writeToFile:[self saveFilePath] atomically:YES];
[myArray release];
And the loading code would be something along the lines of
NSMutableArray* myArray = [[NSMutableArray arrayWithContentsOfFile:[self saveFilePath]]retain];
Then you'd simply load the data back into your array of text fields.
Hope this helps.
It sounds like your application architecture may be unsound if you are planning on saving thousands of text fields' data in the fraction of a second you get while your app is closing. It would probably be better to save these as the user enters the data instead of waiting to save all the data at once.
To get the path you are going to write ( or read from! ) to, you do the following:
NSString *writableDBPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:#"MyFile.extension"];
And then use a method like "writeToFile:automically:" of NSString or NSDictionary etc. to write to the path.