5

I have a situation where I'm lazy loading images from the www.
It's a list of items, when one item is tapped, a detail view is pushed to a nav controller.

In that detail view the item has an image, which first is a default image, and I want to start loading it's image from a URL.

So what I do is create an object which once initialized detaches a new thread which in turn loads the content and afterwards notifies my view that the data is loaded:

// in MyLoader:
- (MyLoader *)initWithUrl:(NSURL *)url requester:(id)requester {
    self.url = url;
    self.requester = requester; // both are nonatomic, retain properties
    [self performSelectorInBackground:@selector(loadIt) withObject:nil];
}

- (void)loadIt {
    NSAutoreleasePool *arp = [[NSAutoreleasePool alloc] init];
    NSData *data = [NSData dataWithContentsOfURL:url];
    [requester performSelectorOnMainThread:@selector(dataReady) withObject:data waitUntilDone:YES;
    [arp release];
}

// in MyRequester:
- (void)somewhere {
    MyLoader *loader = [[[MyLoader] alloc] initWithUrl:someUrl requester:self] autorelease];
    // then I retain loader somewhere, it's more complicated but I have verified that it's properly retained.
}

A few notes:

  1. First I thought there might be a problem with some of the variables. I put a breakpoint right before performSelectorOnMainThread and confirmed that data and requester were both OK.

  2. Then I thought it was caused by passing the NSData across the threads, so I changed withObject:nil. It still crashes.

  3. When I further investigated, the crash was very strange. I specified waitUntilDone:YES, I've placed a breakpoint in the requester's dataReady. But the performSelectorOnMainThread call returns (it reaches the breakpoint after it) while not reaching the breakpoint inside dataReady. BTW, - (void)dataReady:(NSData*)'s body for now only contains int x = 1; (to place a breakpoint on). Also, I've tried setting waitUntilDone:NO, it still crashes.

  4. The selector isn't performed (the breakpoint is not reached), but the crash happens a short while after the call.

Does anyone have any idea what's wrong?

This is obvious, but just to be clear, if I just comment out the [requester performSelectorOnMainThread... part, it doesn't crash.

Also, here's a stack trace, but it's not helpful at all.

#0  0x00a71004 in ___TERMINATING_DUE_TO_UNCAUGHT_EXCEPTION___ ()
#1  0x93436e3b in objc_exception_throw ()
#2  0x0028aca6 in __NSThreadPerformPerform ()
#3  0x00a098e1 in CFRunLoopRunSpecific ()
#4  0x00a08c48 in CFRunLoopRunInMode ()
#5  0x0005a78d in GSEventRunModal ()
#6  0x0005a852 in GSEventRun ()
#7  0x0168a003 in UIApplicationMain ()
#8  0x000028d4 in main (argc=1, argv=0xbffff100) at /Users/myName/Document/appName/main.m:14
Prody
  • 5,182
  • 6
  • 44
  • 62
  • 1
    I suspect there are easier ways of viewing the uncaught exception, but try wrapping int retVal = UIApplicationMain(argc, argv, nil, nil); in your main.m file with a try/catch block and examine or print out the exception. Might give some clues. I know that I'm able to hit continue after something like this (in the debugger) and it eventually prints the cause. But that may be due to some settings in my .gdbinit file. My .gdbinit has some breakpoint things for NSException... – wkw Nov 09 '09 at 00:07

1 Answers1

9

You have:

[requester performSelectorOnMainThread:@selector(dataReady) withObject:data waitUntilDone:YES;

should be:

[requester performSelectorOnMainThread:@selector(dataReady:) withObject:data waitUntilDone:YES;

notice: @selector(dataReady:) (with colon) Since you're passing an argument to the method, it's presumed data ready is defined something like:

- (void) dataReady:(NSData *)theData ...
wkw
  • 3,865
  • 3
  • 25
  • 24
  • 1
    missing colon, not semicolon. The colon is part of the method name. – NSResponder Nov 09 '09 at 04:27
  • 11
    In the future, you can catch this by going to your build settings and adding -Wundeclared-selector in the Other Warning Flags. This will cause a warning to be thrown in the above case, where the selector doesn't match any known method. – Brad Larson Nov 09 '09 at 18:37