我对这两者的使用感到有些困惑。
我有一个后台线程,负责下载数据并将其应用到iOS设备中的核心数据数据库。
后台线程中的代码调用共享实例类ProgressController来更新UI上的进度(我知道在主线程中运行)。然后,ProgressController有一个委托,由顶层的View Controller分配。
它的工作正常,但后台线程启动时UI不会更新。我知道正在调用委托,因为我已经使用正在传递的文本触发了NSLog。
现在我读到我应该使用performSelectorOnMainThread,但鉴于委托正在解雇,这似乎是多余的。
我应该使用performSelectorOnMainThread而不是使用委托。
我错过了什么吗?
如果有人能解释,我会非常感激。
谢谢,
克里斯。
在后台主题中
progressController = [ProgressController sharedInstance];
[progressController open];
...
[progressController updateProgress:NSLocalizedString(@"Update text here", @"Update text here")];
在ProgressController.h中
#import <Foundation/Foundation.h>
@protocol ProgressControllerDelegate
@required
- (void) displayProgress:(NSString *)text;
- (void) showProgress;
- (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
在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
在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;
}
答案 0 :(得分:1)
委托方法本身与线程没有特定的关系。它只是一个向另一个发送消息的对象。如果恰好在后台线程上调用了该委托方法,那么任何UI交互仍然必须在主线程上完成。
某些对象将委托调用与特定线程相关联。例如,NSURLConnection的+ connectionWithRequest:delegate:
,其文档说明:
发送给委托的消息将在调用此方法的线程上发送。为了使连接正常工作,调用线程的运行循环必须在默认的运行循环模式下运行。
因此,简而言之,是的,使用委托方法和performSelectorOnMainThread
来更新UI非常有可能。这样做没有错。
答案 1 :(得分:1)
您插入的代码显示您直接从后台线程调用委托方法。要在主线程(您应该使用)上执行GUI工作,您需要在调用委托方法时或在委托方法本身中直接使用performSelectorOnMainThread:
。如果要在这些更新期间停止后台线程,可以使用waitUntilDone:YES
的变体。
答案 2 :(得分:-1)
您应该使用NSURLConnection类异步下载数据,然后您可以使用其委托方法来更新您的UI
参考此代码 -
// 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];
}
委托方法 -
-(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..
}