私たちは大きなファイルをサーバからバックグラウンドで 'ライブラリ'に同期させる必要があります。 NSOperationのサブクラス化は、iOSタスクのマルチスレッド化の最も柔軟な方法であり、それを試みました。したがって、この関数はダウンロードするURLのリストを受け取り、&保存し、同じNSOperationクラスのインスタンスを初期化し、NSOperationキューに一度に1つのファイルしかダウンロードしないようにします。NSURLConnectionでNSOperationの複数のインスタンスを実行しますか?
-(void) LibSyncOperation {
// Initialize download list. Download the homepage of some popular websites
downloadArray = [[NSArray alloc] initWithObjects:@"www.google.com",
@"www.stackoverflow.com",
@"www.reddit.com",
@"www.facebook.com", nil];
operationQueue = [[[NSOperationQueue alloc]init]autorelease];
[operationQueue setMaxConcurrentOperationCount:1]; // Only download 1 file at a time
[operationQueue waitUntilAllOperationsAreFinished];
for (int i = 0; i < [downloadArray count]; i++) {
LibSyncOperation *libSyncOperation = [[[LibSyncOperation alloc] initWithURL:[downloadArray objectAtIndex:i]]autorelease];
[operationQueue addOperation:libSyncOperation];
}
}
これらのクラスインスタンスはすべて正しく作成され、すべてNSOperationQueueに追加され、実行が開始されます。しかし、問題はダウンロードを開始するときです。最初のファイルはダウンロードされません(デリゲートメソッドでNSURLConnectionを使用)。私は、別のスレッドで見たrunLoopトリックを使用しました。このトリックは、ダウンロードが完了するまで動作を継続できるようにする必要があります。 NSURLConnectionは確立されますが、NSMutableDataオブジェクトへのデータの追加が開始されません。
@synthesize downloadURL, downloadData, downloadPath;
@synthesize downloadDone, executing, finished;
/* Function to initialize the NSOperation with the URL to download */
- (id)initWithURL:(NSString *)downloadString {
if (![super init]) return nil;
// Construct the URL to be downloaded
downloadURL = [[[NSURL alloc]initWithString:downloadString]autorelease];
downloadData = [[[NSMutableData alloc] init] autorelease];
NSLog(@"downloadURL: %@",[downloadURL path]);
// Create the download path
downloadPath = [NSString stringWithFormat:@"%@.txt",downloadString];
return self;
}
-(void)dealloc {
[super dealloc];
}
-(void)main {
// Create ARC pool instance for this thread.
// NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init]; //--> COMMENTED OUT, MAY BE PART OF ISSUE
if (![self isCancelled]) {
[self willChangeValueForKey:@"isExecuting"];
executing = YES;
NSURLRequest *downloadRequest = [NSURLRequest requestWithURL:downloadURL];
NSLog(@"%s: downloadRequest: %@",__FUNCTION__,downloadURL);
NSURLConnection *downloadConnection = [[NSURLConnection alloc] initWithRequest:downloadRequest delegate:self startImmediately:NO];
// This block SHOULD keep the NSOperation from releasing before the download has been finished
if (downloadConnection) {
NSLog(@"connection established!");
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!downloadDone);
} else {
NSLog(@"couldn't establish connection for: %@", downloadURL);
// Cleanup Operation so next one (if any) can run
[self terminateOperation];
}
}
else { // Operation has been cancelled, clean up
[self terminateOperation];
}
// Release the ARC pool to clean out this thread
//[pool release]; //--> COMMENTED OUT, MAY BE PART OF ISSUE
}
#pragma mark -
#pragma mark NSURLConnection Delegate methods
// NSURLConnectionDelegate method: handle the initial connection
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse*)response {
NSLog(@"%s: Received response!", __FUNCTION__);
}
// NSURLConnectionDelegate method: handle data being received during connection
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[downloadData appendData:data];
NSLog(@"downloaded %d bytes", [data length]);
}
// NSURLConnectionDelegate method: What to do once request is completed
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(@"%s: Download finished! File: %@", __FUNCTION__, downloadURL);
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex:0];
NSString *targetPath = [docDir stringByAppendingPathComponent:downloadPath];
BOOL isDir;
// If target folder path doesn't exist, create it
if (![fileManager fileExistsAtPath:[targetPath stringByDeletingLastPathComponent] isDirectory:&isDir]) {
NSError *makeDirError = nil;
[fileManager createDirectoryAtPath:[targetPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:&makeDirError];
if (makeDirError != nil) {
NSLog(@"MAKE DIR ERROR: %@", [makeDirError description]);
[self terminateOperation];
}
}
NSError *saveError = nil;
//NSLog(@"downloadData: %@",downloadData);
[downloadData writeToFile:targetPath options:NSDataWritingAtomic error:&saveError];
if (saveError != nil) {
NSLog(@"Download save failed! Error: %@", [saveError description]);
[self terminateOperation];
}
else {
NSLog(@"file has been saved!: %@", targetPath);
}
downloadDone = true;
}
// NSURLConnectionDelegate method: Handle the connection failing
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"%s: File download failed! Error: %@", __FUNCTION__, [error description]);
[self terminateOperation];
}
// Function to clean up the variables and mark Operation as finished
-(void) terminateOperation {
[self willChangeValueForKey:@"isFinished"];
[self willChangeValueForKey:@"isExecuting"];
finished = YES;
executing = NO;
downloadDone = YES;
[self didChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isFinished"];
}
#pragma mark -
#pragma mark NSOperation state Delegate methods
// NSOperation state methods
- (BOOL)isConcurrent {
return YES;
}
- (BOOL)isExecuting {
return executing;
}
- (BOOL)isFinished {
return finished;
}
注:それはあまりにも読めないだった場合、私はあなたを介して見ることができるQUICK GITHUB PROJECT HEREを設定します。ご迷惑をおかけして申し訳ありません。
私はそれがクラス変数の保持/解放と関係があると思われますが、クラスをインスタンス化すると各インスタンスにクラス変数のセットが与えられると思っていたので、それを確認することはできません。私はすべてを試してみましたが、私は答えを見つけることができません、どんな助け/提案も大いに感謝されるでしょう!
更新:私の答えは以下の通りですが、この問題を少し前に解決し、GitHub projectをワーキングコードで更新しました。うまくいけば、あなたがここに来て同じことを探しているなら、それは助けになる!
あなたの問題の最も直接的な解決策ではないかもしれませんが、あなたの操作はバックグラウンドで実行されるので、NSURLConnnectionを使う必要はないでしょう。単に+ [NSData dataWithContentsOfURL:] 'これは実行ループを必要としません。 – jtbandes
確かに可能ですが、その同期メソッドを使用する際の主な問題は、NSURLConnectionデリゲートメソッドのような確実なエラー処理を許可しないことです。私は誰も私のための答えがない場合は恐れている私はそれと一緒に行かなければならない:/ – andycam
それは価値があることについては、私はこれが可能であると確信しています - 今はそれを探す時間があります。おそらく、より深刻なグーグルが助けになるだろう。運が良かった! – jtbandes