Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 在NSThread或NSOperation内部使用NSUrlConnection_Ios_Nsurlconnection_Nsthread_Nsoperation_Synchronous - Fatal编程技术网

Ios 在NSThread或NSOperation内部使用NSUrlConnection

Ios 在NSThread或NSOperation内部使用NSUrlConnection,ios,nsurlconnection,nsthread,nsoperation,synchronous,Ios,Nsurlconnection,Nsthread,Nsoperation,Synchronous,我正在开发一个静态库,它需要在后台做一些事情,而不需要与主线程交互。为了给您一个想法,可以考虑只记录一些用户事件。库必须一直这样做,直到用户退出应用程序或将其发送到后台(按下home按钮)——换句话说,它需要在循环中继续这样做 主应用程序线程和衍生线程之间的唯一交互是,偶尔主应用程序线程会将一些内容(事件对象)放入衍生线程可以读取/使用的队列中。除此之外,生成的线程会一直运行,直到应用程序存在或出现 生成的线程需要做的部分工作(尽管不是全部)包括向HTTP服务器发送数据。我本以为可以很容易地将N

我正在开发一个静态库,它需要在后台做一些事情,而不需要与主线程交互。为了给您一个想法,可以考虑只记录一些用户事件。库必须一直这样做,直到用户退出应用程序或将其发送到后台(按下home按钮)——换句话说,它需要在循环中继续这样做

主应用程序线程和衍生线程之间的唯一交互是,偶尔主应用程序线程会将一些内容(事件对象)放入衍生线程可以读取/使用的队列中。除此之外,生成的线程会一直运行,直到应用程序存在或出现

生成的线程需要做的部分工作(尽管不是全部)包括向HTTP服务器发送数据。我本以为可以很容易地将NSThread子类化,重写其主方法,然后在连接上使用某种超时对NSUrlConnection进行同步调用,这样线程就不会永远挂起。例如,在Java/Android中,我们只是对Thread进行子类化,重写start()方法并调用同步HTTP GET方法(比如从Apache的HttpClient类)。这是非常容易和工作良好。但从我在这里和其他地方看到的情况来看,显然在iOS上,它比这复杂得多,我有点困惑,到底什么才是最有效的方法


那么,我应该将NSThread子类化并以某种方式使用NSUrlConnection吗?异步NSUrlConnection似乎在NSThread内不起作用,因为委托方法不会被调用,但是同步方法呢?我是否需要使用和配置RunLoop并设置自动释放池?还是应该使用NSO操作?在我看来,我正在尝试做的事情是非常常见的-有没有人有一个如何正确执行此操作的工作示例?

据我所知,要异步使用
NSURLConnection
,您需要一个runloop。即使您使用
NSOperation
,您仍然需要一个runloop

我看到的所有示例都使用
主线程
来启动
NSURLConnection
,它有一个runloop。使用
NSOperation
的示例设置为
Concurrent
,告诉
NSOperationQueue
不要提供自己的线程,然后确保在主线程上启动
NSURLConnection
,例如通过调用
performselectornmainthread:

以下是一个例子:

您还可以在苹果文档中搜索
LinkedImageFetcher
示例中的
QRunLoopOperation
,该示例类显示了此类内容的一些细节


(虽然我不确定我是否真的看到过任何示例中显示如何运行自己的runloop的代码,但这个示例同样依赖于主线程。)

我使用了grand central dispatch(GCD)方法来实现这一点。下面是一个在简单测试应用程序中对我有用的示例(我不确定它是否适用于静态库,但可能值得一看)。我用的是ARC

在本例中,我将从viewDidLoad方法开始一些背景工作,但您可以从任何地方开始。关键是“dispatch_async(dispatch_get_global_queue…”在后台线程中运行块。有关该方法的详细说明,请参阅此答案:

以下是我的viewDidLoad:

- (void)viewDidLoad
{
    [super viewDidLoad];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL), 
        ^(void) {
            [self doStuffInBackground];
        });
}
doStuffInBackground方法此时正在后台运行,因此您可以同步使用NSURLConnection。在我这里的示例中,该方法循环进行网络调用,直到可能有其他代码集backgroundStuffShouldRun=false。网络调用超时10秒。调用后,我正在更新UI标签just以显示进度。请注意,UI更新是使用“dispatch_async(dispatch_get_main_queue()…”执行的。这将根据需要在UI线程上运行UI更新

此后台工作的一个潜在问题是:无法取消http请求本身。但是,如果超时10秒,则在外部人员(可能是UI中的某个事件)设置backgroundStuffShouldRun=false后,您最多需要等待10秒,线程才会自行中止

- (void)doStuffInBackground
{
    while (backgroundStuffShouldRun) {
        // prepare for network call...
        NSURL* url = [[NSURL alloc] initWithString:@"http://maps.google.com/maps/geo"];

        // set a 10 second timeout on the request
        NSURLRequest* request = [[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLCacheStorageAllowed timeoutInterval:10];

        NSError* error = nil;
        NSURLResponse *response = nil;

        // make the request
        NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

        // were we asked to stop the background processing?
        if (!backgroundStuffShouldRun) {
            return;
        }

        // process response...

        NSString* status = @"Success";

        if (error) {
            if (error.code == NSURLErrorTimedOut) {
                // handle timeout...
                status = @"Timed out";
            }
            else {
                // handle other errors...
                status = @"Other error";
            }
        }
        else {
            // success, handle the response body
            NSString *dataAsString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"%@", dataAsString);
        }


        // update the UI with our status
        dispatch_async(dispatch_get_main_queue(), ^{
            [statusLabel setText:[NSString stringWithFormat:@"completed network call %d, status = %@", callCount, status]];
        });

        callCount++;
        sleep(1); // 1 second breather. not necessary, but good idea for testing
    }

}