Note that there are some explanatory texts on larger screens.

plurals
  1. POUpdating an NSmenu from an asynchronous NSURLConnection
    primarykey
    data
    text
    <p>I am writing a little systray application that fetches data from an API and updates its menu accordingly, and am having trouble with updating the menu while it's open.</p> <p>I don't even know where to start, so let's start with the beginning.</p> <p>I have a custom <code>PNLinksLoader</code> class whose responsibility is to fetch the data and parse it:</p> <pre><code>- (void)loadLinks:(id)sender { // instance variable used by the NSXMLParserDelegate implementation to store data links = [NSMutableArray array]; [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data]; parser.delegate = self; if (YES == [parser parse]) { NSArray *modes = [NSArray arrayWithObject:NSRunLoopCommonModes]; [delegate performSelectorOnMainThread:@selector(didEndLoadLinks:) withObject:links waitUntilDone:NO modes:modes]; } }]; } </code></pre> <p>The loader is ran one time at the application's startup (works perfectly), and then a timer is setup for periodic refresh:</p> <pre><code>loader = [[PNLinksLoader alloc] init]; [loader setRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://papyrus.pandanova.com/links"]]]; [loader setDelegate:self]; [loader loadLinks:self]; NSMethodSignature *signature = [loader methodSignatureForSelector:@selector(loadLinks:)]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; [invocation setTarget:loader]; [invocation setSelector:@selector(loadLinks:)]; NSTimer *timer = [NSTimer timerWithTimeInterval:10 invocation:invocation repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; </code></pre> <p>Now whenever the loader loads new data on the server, if the menu is closed, then everything is ok, I open the menu and the new data is there.</p> <p>But if the menu happens to be open during the refresh, then nothing happens. If I close and reopen the menu, then I can see the new data.</p> <p>I think I'm missing something about the RunLoop, but I fail to see what (my understanding of it is very sparse, as I'm actually writing this little app mainly to learn Objective-C).</p> <p><strong>EDIT</strong></p> <p>The problem here is not to update the menu while it is open, it actually kind of works when I use <code>performSelector:withObject:</code> instead of <code>performSelectorOnMainThread:withObject:waitUntilDone:modes:</code> in the loader. The thing is when I do that I get weird results when updating the menu while it's open (works perfectly when the menu is closed):</p> <p><img src="https://i.stack.imgur.com/ScQZJ.png" alt="weird behavior"></p> <p>Adding an <code>NSLog</code> call in my menu population loop <code>fixes</code> the symptoms, and from what I read on the internet, it might be a sign that I have a race condition on my threads (that's why I tried using <code>performSelectorOnMainThread</code>, but I can't seem to figure it out.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload