菜鸟教程小白 发表于 2022-12-12 19:37:56

ios - 使用 NSURLConnection 运行多个 NSOperation 实例?


                                            <p><p>我们有一个大型项目,需要将大型文件从服务器同步到后台的“库”中。我读过子类化 NSOperation 是多线程 iOS 任务的最灵活方式,并尝试过。因此,该函数接收要下载和保存的 URL 列表,初始化同一 NSOperation 类的实例并将每个实例添加到 NSOperation 队列(一次只能下载一个文件)。</p>

<pre><code>-(void) LibSyncOperation {   
    // Initialize download list. Download the homepage of some popular websites
    downloadArray = [ initWithObjects:@&#34;www.google.com&#34;,
                                                   @&#34;www.stackoverflow.com&#34;,
                                                   @&#34;www.reddit.com&#34;,
                                                   @&#34;www.facebook.com&#34;, nil];

    operationQueue = [[init]autorelease];
    ; // Only download 1 file at a time
    ;

    for (int i = 0; i &lt; ; i++) {
      LibSyncOperation *libSyncOperation = [[ initWithURL:]autorelease];
      ;
    }
}
</code></pre>

<p>现在,这些类实例都可以正常创建,并且都添加到 NSOperationQueue 并开始执行。但问题是何时开始下载,第一个文件永远不会开始下载(使用带有委托(delegate)方法的 NSURLConnection )。我使用了我在另一个线程中看到的 runLoop 技巧,它应该允许操作继续运行,直到下载完成。 NSURLConnection 已建立,但它从未开始将数据附加到 NSMutableData 对象!</p>

<pre><code>@synthesize downloadURL, downloadData, downloadPath;
@synthesize downloadDone, executing, finished;

/* Function to initialize the NSOperation with the URL to download */
- (id)initWithURL:(NSString *)downloadString {

    if (!) return nil;

    // Construct the URL to be downloaded
    downloadURL = [[initWithString:downloadString]autorelease];
    downloadData = [[ init] autorelease];

    NSLog(@&#34;downloadURL: %@&#34;,);

    // Create the download path
    downloadPath = ;
    return self;
}

-(void)dealloc {
    ;
}

-(void)main {

    // Create ARC pool instance for this thread.   
    // NSAutoreleasePool *pool = [init]; //--&gt; COMMENTED OUT, MAY BE PART OF ISSUE

    if (!) {

      ;
      executing = YES;

      NSURLRequest *downloadRequest = ;
      NSLog(@&#34;%s: downloadRequest: %@&#34;,__FUNCTION__,downloadURL);
      NSURLConnection *downloadConnection = [ initWithRequest:downloadRequest delegate:self startImmediately:NO];

      // This block SHOULD keep the NSOperation from releasing before the download has been finished
      if (downloadConnection) {
            NSLog(@&#34;connection established!&#34;);
            do {
                [ runMode:NSDefaultRunLoopMode beforeDate:];
            } while (!downloadDone);

      } else {
            NSLog(@&#34;couldn&#39;t establish connection for: %@&#34;, downloadURL);

            // Cleanup Operation so next one (if any) can run
            ;
      }
            }
    else { // Operation has been cancelled, clean up
      ;
    }

// Release the ARC pool to clean out this thread
//;   //--&gt; 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(@&#34;%s: Received response!&#34;, __FUNCTION__);
}

// NSURLConnectionDelegate method: handle data being received during connection
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    ;
    NSLog(@&#34;downloaded %d bytes&#34;, );
}

// NSURLConnectionDelegate method: What to do once request is completed
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
    NSLog(@&#34;%s: Download finished! File: %@&#34;, __FUNCTION__, downloadURL);
    NSFileManager *fileManager = ;
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docDir = ;
    NSString *targetPath = ;
    BOOL isDir;

    // If target folder path doesn&#39;t exist, create it
    if (! isDirectory:&amp;isDir]) {
      NSError *makeDirError = nil;
       withIntermediateDirectories:YES attributes:nil error:&amp;makeDirError];
      if (makeDirError != nil) {
            NSLog(@&#34;MAKE DIR ERROR: %@&#34;, );
            ;
      }
    }

    NSError *saveError = nil;
    //NSLog(@&#34;downloadData: %@&#34;,downloadData);
    ;
    if (saveError != nil) {
      NSLog(@&#34;Download save failed! Error: %@&#34;, );
      ;
    }
    else {
      NSLog(@&#34;file has been saved!: %@&#34;, targetPath);
    }
    downloadDone = true;
}

// NSURLConnectionDelegate method: Handle the connection failing
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@&#34;%s: File download failed! Error: %@&#34;, __FUNCTION__, );
    ;
}

// Function to clean up the variables and mark Operation as finished
-(void) terminateOperation {
    ;
    ;
    finished = YES;
    executing = NO;
    downloadDone = YES;
    ;
    ;
}

#pragma mark -
#pragma mark NSOperation state Delegate methods
// NSOperation state methods
- (BOOL)isConcurrent {
    return YES;
}
- (BOOL)isExecuting {
    return executing;
}
- (BOOL)isFinished {
    return finished;
}
</code></pre>

<p>注意:如果这太难以理解,我设置了 <a href="https://github.com/APPronaut/iOS-Simultaneous-Async-NSURLConnections" rel="noreferrer noopener nofollow">QUICK GITHUB PROJECT HERE</a>你可以看看。请注意,我不希望任何人为我工作,只是为我的问题寻找答案!</p>

<p>我怀疑它与保留/释放类变量有关,但我不能确定这一点,因为我认为实例化一个类会给每个实例自己的一组类变量。我已经尝试了一切,但我找不到答案,任何帮助/建议将不胜感激!</p>

<p><strong>更新:根据我下面的回答,我不久前解决了这个问题并更新了 <a href="https://github.com/APPronaut/iOS-Simultaneous-Async-NSURLConnections" rel="noreferrer noopener nofollow">GitHub project</a>与工作代码。希望如果您来这里是为了寻找同样的东西,它会有所帮助!</strong></p></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>出于良好的社区实践和帮助可能遇到同样问题的其他人的利益,我最终解决了这个问题并更新了 <a href="https://github.com/andy-cam/iOS-Simultaneous-Async-NSURLConnections" rel="noreferrer noopener nofollow"><strong>GitHub sample project here</strong></a>现在可以正常工作,即使是多个并发的 NSOperations!</p>

<p>最好查看 GitHub 代码,因为我进行了大量更改,但我必须进行的关键修复是:</p>

<pre><code> forMode:NSDefaultRunLoopMode];
</code></pre>

<p>这在 NSURLConnection 初始化之后调用,就在它启动之前。它将连接的执行附加到当前的主运行循环,以便 NSOperation 在下载完成之前不会过早终止。我很想感谢第一次发布这个聪明的修复的地方,但是太久了,我忘记了在哪里,道歉。希望这对某人有帮助!</p></p>
                                   
                                                <p style="font-size: 20px;">关于ios - 使用 NSURLConnection 运行多个 NSOperation 实例?,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/9684770/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/9684770/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - 使用 NSURLConnection 运行多个 NSOperation 实例?