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;
Related
I did not find any suitable answers on the web, so I post my question here.
__block int test = 1;
dispatch_async(dispatch_get_main_queue(), ^{
test = 2;
});
NSLog(#"%i",test);
This code will result in console message "1".
__block NSString *test = #"no";
dispatch_async(dispatch_get_main_queue(), ^{
test = #"yes";
});
NSLog(#"%#",test);
This code will result in console message "no".
Why is it so? I thought that __block identifier should solve all problems in this case.
My hypothesis is that local variable was copied and code inside block hadn't actually modify anything outside itself.
How can I modify local variables inside dispatch_async?
Sorry if it is a noob question.
You are dispatching asynchronously to the main queue.
The dispatch_async returns before the block is executed (coincidentally).
To underscore how non-deterministic concurrent programming can be:
Note that your NSLog() might sometimes see the new value maybe once in a very blue moon. You might not ever see it in your debugging environment, but some customer might encounter that behavior 3 years from now on a system configuration that doesn't exist today.
To fix?
dispatch_sync() thereby ensuring that your background queue and the main queue are effectively acting like a less efficient single serial queue.
... or ...
Use some kind of synchronization construct to message from the main queue back to your local queue when the operation is done. I.e.:
dispatch_async(otherQueue, ^{
... do something ...;
dispatch_async(firstQueue, ^{
done(calculatedValue);
};
};
You are dispatching setting test asynchronously, meaning your NSLog statement is going to fire before the block.
You would have to do it this way, or change it to a dispatch_sync.
__block NSString *test = #"no";
dispatch_async(dispatch_get_main_queue(), ^{
test = #"yes";
NSLog(#"%#",test);
});
If you need to do something on a background thread and then pop it back onto the main thread, just do the following:
__block NSString *test = #"no";
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
test = #"setting Testing in the background";
NSLog(#"Printing from the background:%#",test);
dispatch_async(dispatch_get_main_queue(), ^{
test = #"Setting Test on the main thread";
NSLog(#"Logging test on the main thread:%#",test);
});
});
You are calling dispatch_async. Although you are executing the code on the main thread, it is still not determined wether the code "test = #"yes" gets executed before the "NSLog(#"%#",test);" code.
If you use dispatch_sync it will work as expexted.
I have this code:
-(void)getData:(NSString *)data: (id) tv: (id) soc
{
NSLog(#"\nin get data with data\n");
NSLog(data);
After a few hours the app crashes and it reaches in get data with data and doesn't print the data so it's crashing on the print of the data. The debug references the failure in something like a string length function. In XCode, data has a warning that it is not a string literal and potentially insecure. Now my experience tells me the most likely culprit is data is somehow null. But it also printed in the log something that looks like it received a typical message. it said it has 131 bytes from the socket. When i tested and it crashed last time it has 189 bytes. but it never prints it.
The data is sent in from the socket liket this in receive data:
UInt8 buffer[len];
NSLog(#"Received %d bytes from socket %d\n",
len, CFSocketGetNative(s));
CFDataGetBytes(df, range, buffer);
NSString *oldtext = [mTextViewAlias text];
char buffer2[len];
for(int a=0; a<len; a++)
buffer2[a]=buffer[a];
NSMutableData *buffer3 = [[NSMutableData alloc] init];
[buffer3 appendBytes:buffer2 length:len];
NSString *newdata = [[NSString alloc] initWithData: buffer3 encoding:NSASCIIStringEncoding];
and the call to the class method that is crashing when it prints the data is just:
[mytelnet getData:newdata:mTextViewAlias:(__bridge id)(s)];
Could i have a memory leak or something and after a few hours i'm out of memory causing the assignment of new data to be null even if i start out with some 100 bytes? Would it crash only when i tried to print data in the nslog and not earlier if it failed to allocate memory?
Mike
Instead of
NSLog(data);
use
NSLog(#"%#",data);
That may not solve your root cause but you get rid of the warning and may get some more reasonalbe and helpful debug output.
You might get rid of that crash too. Hovever this is not a promise.
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.
I have a UITableView which displays images. Every cell has an image and every time a cell loads, I call a selector (from the cellForRowAtIndexPath) in the background like this:
[self performSelectorInBackground:#selector(lazyLoad:) withObject:aArrayOfData];
The only problem is that sometimes I get a crash (because I am changing data in the background while it's trying to be read elsewhere). Here's the error:
*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <CALayerArray: 0xce1a920> was mutated while being enumerated.'
When updating the data in the background, should I move it to the main selector and change it? Or should I call the #selector() differently?
Thanks!
If you can leave the operation on the main thread and have no lagginess nor problems you are done.
However: Let's assume you've already done that and encounter problems. The answer is: don't modify the array in the lazy load. Switch to the main thread to modify the array. See Brad's answer here:
https://stackoverflow.com/a/8186206/8047
for a way to do it with blocks, so you can send your objects over to the main queue (you should probably also use GCD for the call to the lazy load in the first place, but it's not necessary).
You can use #synchronized blocks to keep the threads from walking over each other. If you do
#synchronized(array)
{
id item = [array objectAtIndex:row];
}
in the main thread and
#synchronized(array)
{
[array addObject:item];
}
in the background, you're guaranteed they won't happen at the same time. (Hopefully you can extrapolate from that to your code—I'm not sure what all you're doing with the array there..)
It seems, though, like you'd have to notify the main thread anyway that you've loaded the data for a cell (via performSelectorOnMainThread:withObject:waitUntilDone:, say), so why not pass the data along, too?
Given the term 'lazy load' I am assuming that means you are pulling your images down from a server. (If the images are local then there is really no need for multithreading).
If you are downloading images off a server I would suggest using something along these lines (using ASIHTTPRequest)
static NSCache *cellCache; //Create a Static cache
if (!cellCache)//If the cache is not initialized initialize it
{
cellCache = [[NSCache alloc] init];
}
NSString *key = imageURL;
//Look in the cache for image matching this url
NSData *imageData = [cellCache objectForKey:key];
if (!imageData)
{
//Set a default image while it's loading
cell.icon.image = [UIImage imageNamed:#"defaultImage.png"];'
//Create an async request to the server to get the image
__unsafe_unretained ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:imageURL]];
//This code will run when the request finishes
[request setCompletionBlock:^{
//Put downloaded image into the cache
[cellCache setObject:[request responseData] forKey:key];
//Display image
cell.icon.image = [UIImage imageWithData:[request responseData]];
}];
[request startAsynchronous];
}
else
{
//Image was found in the cache no need to redownload
cell.icon.image = [UIImage imageWithData:imageData];
}
Im a bit confused here, Im using queues and I got to a point where Im a bit lost.
I have a method named getPeople who has to fetch pictures of users from the server. In order not to block the app I used this:
-(IBAction)seeMorePeople{
dispatch_queue_t getPeopleQueue = dispatch_queue_create("Pinta Ocupantes", NULL);
dispatch_async(getPeopleQueue, ^{
[self getPeople];
});
dispatch_release(getPeopleQueue);
}
The previous code is executed everytime the user taps a button. Something like "Give me pics from this album" and then another tap "Now I want people's pictures from that other album", diferent pics and different amount of pictures. If the user taps the buttons quite fast, the first queue wont finish fetching the data when the second one is already starting. With in getPeople I store the data in an NSMutableArray, so when the 2 queues are executing at the same time both are writing on the same Array and the app crashes due to out of bounds exception.
The way getPeople goes through the data is something like this:
-(void)getPeople:(NSDictionary *)peopleDictionary{
//I receive an NSDictionary and I go through it
NSArray *keys = [peopleDictionary allKeys];
int indexOfArray = 0;
for(NSString *key in keys){
//Complex operation that are not important
[peopleInArray insertObjetAtIndex:indexOfArray];//People in array is a global variable
indexOfArray++;
}
}
What I can't figure out is how to get out of this, I thought of stopping the first queue when the second one comes in, but GCD doesnt have this option... any other way to get this done, hopefully without a major recoding, anyway right now Im out of ideas, so any clue will help.
I would suggest that you avoid synchronizing with semaphores, if possible. The design of GCD is to avoid that. A background task should prepare data but not touch outside state. When the data is prepared, it should dispatch the updating of outside state to either a serial queue or, if the state is bound to the GUI, to the main queue.
So, something like this:
-(void)getPeople:(NSDictionary *)peopleDictionary{
//I receive an NSDictionary and I go through it
NSArray *keys = [peopleDictionary allKeys];
for(NSString *key in keys){
//Complex operation that are not important
dispatch_async(dispatch_get_main_queue(), ^{
[peopleInArray addObject:<whatever>];
});
}
}
If you rather want to replace the array, instead of having two threads adding to it in interleaved fashion, you'd accumulate the whole array in the background and dispatch setting the entirety of peopleInArray to the main queue.
If you want cancellation, you can implement it yourself with a flag, or you should maybe consider using NSOperation and NSOperationQueue instead of GCD. Those have a concept of cancellation built in, although your custom operations still need to check if they've been cancelled and stop working.
You are right, there is no way to stop a queue which was dispatched. One thing you could do to make sure that only one queue is accessing getPeople at the same time is using semaphores (this might be even more interesting).
If you just want to avoid that the users clicks the button multiple times you could use a bool variable stillExecuting which is set to YES in your asynchronous dispatch and set to NO at the end of getPeople. Before creating getPeopleQueue you simply check if getPeople is still executing.
if(!stillExecuting) {
dispatch_queue_t getPeopleQueue = dispatch_queue_create("Pinta Ocupantes", NULL);
dispatch_async(getPeopleQueue, ^{
[self getPeople];
});
dispatch_release(getPeopleQueue);
}
NSString *lastLoginTime =#" Your last login time";
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSDate* date1 = [dateFormat lastLoginTime];
NSDate* date2 = [dateFormat dateFromString:[NSString currentDateTime]];
NSTimeInterval secondsSinceLastLogin = [date2 timeIntervalSinceDate:date1];
// NSLog(#"Seconds Since Last Login: %g", secondsSinceLastLogin);
int hours = (int)secondsSinceLastLogin / 3600;