2

私はこれら2つの使用について少し混乱しています。

データをダウンロードして iOS デバイス内の Core Data Database に適用するという面倒な作業を行うバックグラウンド スレッドがあります。

バックグラウンド スレッド内のコードは、共有インスタンス クラス ProgressController を呼び出して、UI の進行状況を更新します (これはメイン スレッドで実行されることがわかっています)。次に、ProgressController には、一番上にある View Controller によって割り当てられるデリゲートがあります。

バックグラウンド スレッドが開始されると UI が更新されないことを除いて、すべて正常に動作します。通過するテキストで NSLogs を起動しているため、デリゲートが呼び出されていることがわかります。

今、私は 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;

}
4

3 に答える 3

1

挿入されたコードは、バックグラウンド スレッドからデリゲート メソッドを直接呼び出すことを示しています。メイン スレッド (想定されている) で GUI 作業を実行するにはperformSelectorOnMainThread:、デリゲートのメソッドを呼び出すときに直接使用するか、デリゲート メソッド自体で使用する必要があります。これらの更新中にバックグラウンド スレッドを停止したい場合は、バリアントをwaitUntilDone:YES.

于 2011-04-18T12:49:51.600 に答える
1

デリゲート メソッド自体には、スレッドとの特定の関係はありません。それは単に、メッセージを別のオブジェクトに送信する 1 つのオブジェクトです。そのデリゲート メソッドがバックグラウンド スレッドで呼び出された場合でも、UI の操作はすべてメイン スレッドで行う必要があります。

詳細については、次のドキュメントを参照してください 。 SW18

一部のオブジェクトは、デリゲートの呼び出しを特定のスレッドに関連付けます。たとえば、+ connectionWithRequest:delegate:ドキュメントには次のように記載されている NSURLConnection の があります。

デリゲートへのメッセージは、このメソッドを呼び出すスレッドで送信されます。接続が正しく機能するには、呼び出しスレッドの実行ループがデフォルトの実行ループ モードで動作している必要があります。

つまり、はい、両方のデリゲート メソッドを使用しperformSelectorOnMainThreadて UI を更新することは非常に可能です。そうすることに何の問題もありません。

于 2011-04-18T12:14:33.130 に答える
-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.. 

}
于 2011-04-18T11:37:54.207 に答える