开发者

Delegates and performSelectorOnMainThread

I'm slightly confused over the use of these two.

I have a background thread which does the heavy lifting of downloading data and applying it to the Core Data Database within the iOS device.

The code within the background thread calls a shared instance class ProgressController to update progress on the UI (which I know runs in the main thread). ProgressController then has a delegate which is assigned by the View Controller on top.

Its all working fine, except that the UI does not update once the background thread has started. I know the delegate is being called because I have NSLogs firing with the text that's being passed through.

Now I read that I should be using performSelectorOnMainThread, but that seems superfluous given that the delegate is firing.

Should I use performSelectorOnMainThread instead and not use delegates at all.

Am I missing something?

If someone could explain, I'd be really grateful.

Thanks,

Chris.

Within Background Thread

progressController = [ProgressController sharedInstance];
[progressController open];

....

[progressController updateProgress:NSLocalizedString(@"Update text here", @"Update text here")];

Within ProgressController.h

#import <Foundation/Foundation.h>

@protocol ProgressControllerDelegate 
@required
- (void) displayProgress:(NSString *)text;
- (void) showPr开发者_开发问答ogress;
- (void) hideProgress;

@end

@interface  ProgressController : NSObject {

    NSString    *currentProgress;
    BOOL        progressOnDisplay;
    id          delegate;
}

+ (ProgressController *)sharedInstance;

@property (nonatomic) BOOL  progressOnDisplay;
@property (nonatomic, assign) id delegate;

-(void) open;
-(void) updateProgress:(NSString *)text;
-(void) reDisplayProgress;
-(void) close;

@end

Within ProgressController.m #import "ProgressController.h"

@implementation ProgressController

@synthesize progressOnDisplay;
@synthesize delegate;

static ProgressController *sharedInstance;

+ (ProgressController *)sharedInstance {
    @synchronized(self) {
        if (!sharedInstance)
        [[ProgressController alloc] init];              
    }
    return sharedInstance;
}

+(id)alloc {
    @synchronized(self) {
        NSAssert(sharedInstance == nil, NSLocalizedString(@"Attempted to allocate a second instance of a singleton ProgressController.", @"Attempted to allocate a second instance of a singleton ProgressController."));
        sharedInstance = [super alloc];
    }
    return sharedInstance;
}
-(id) init {
    if (self = [super init]) {
        [self open];
    }
    return self;
}

// Ask delegate to show new Progress Label
-(void) open {
    progressOnDisplay = TRUE;
    currentProgress = @"";
    [self.delegate showProgress];
}

// Ask delegate to update and display Progress text
-(void) updateProgress:(NSString *)text {
    currentProgress = text;
    [self.delegate displayProgress:currentProgress];

}

// Ask delegate display existing Progress text if any
-(void) reDisplayProgress {
    if (currentProgress != @"") {
        [self.delegate displayProgress:currentProgress];
        [self.delegate showProgress];   
    }
}

// Ask delegate to clear and hide Progress Label
-(void) close {
    progressOnDisplay = FALSE;
    currentProgress = @"";
    [self.delegate hideProgress];
}


@end

Within View Controller

- (void)viewDidLoad {
    [super viewDidLoad];

    progressController = [ProgressController sharedInstance];
    progressController.delegate = self;
    [progressController reDisplayProgress]; // In case progress has been updated prior to the view load

}

// Delegate method to show Progress Label
- (void) showProgress {
    progressView.hidden = FALSE;    

}

// Delegate method to display specific text in Progress label
- (void) displayProgress:(NSString *)text {
    [progressLabel setText:text];
    [progressView setNeedsDisplay];

    DLog(@"Reporting -  %s", [text UTF8String]);  // I can see that this is firing successfully

}

// Delegate method to hide Progress Label
- (void) hideProgress {
    progressView.hidden = TRUE;

}


Your inserted code shows that you call the delegate method directly from the background thread. To perform the GUI work on the main thread (which you are supposed to), you need to use performSelectorOnMainThread: either directly when calling the delegate's methods or in the delegate methods themselves. If you want to stop your background thread during these updates, you might use the variants with waitUntilDone:YES.


A delegate method on its own has no specific relationship with a thread. It's simply one object sending a message to another. If that delegate method happens to be called on a background thread, then any UI interaction must still be done on the main thread.

For more info, see the docs: http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/CocoaFundamentals/CommunicatingWithObjects/CommunicateWithObjects.html%23//apple_ref/doc/uid/TP40002974-CH7-SW18

Some objects associate delegate invocations with a particular thread. For example, NSURLConnection's + connectionWithRequest:delegate: , whose documentation states:

Messages to the delegate will be sent on the thread that calls this method. For the connection to work correctly the calling thread’s run loop must be operating in the default run loop mode.

So, in short, yes, it's very possible to use both delegate methods and performSelectorOnMainThread to update your UI. There's nothing wrong with doing that.


you should download the data asynchronously using the NSURLConnection class then you can use its delegate methods to update your UI

refer this code -

    // create the URL
    NSURL *postURL = [NSURL URLWithString:@"http://twitpic.com/api/uploadAndPost"];

    // create the connection
    NSMutableURLRequest *postRequest = [NSMutableURLRequest requestWithURL:postURL
                                                               cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                           timeoutInterval:30.0];

    // change type to POST (default is GET)
    [postRequest setHTTPMethod:@"POST"];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:postRequest delegate:self];

    if( theConnection )
    {
        webData = [[NSMutableData data] retain];
    }

Delegate methods -

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    [webData setLength: 0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// update your UI here.. 
    [webData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    NSLog(@"ERROR with theConenction");
    [connection release];
    [webData release];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//  your data downloaded completely.. do you code here.. 

}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜