iOS后台下载

时间:2015-10-07 01:23:12

标签: ios background-thread

我有一个应用程序需要在用户登录时下载大量数据。我想将其下载部分移动到后台线程,以便用户可以导航应用程序而无需等待下载完成。我尝试了以下方法,但其中一些仍然锁定了应用程序,因此用户无法点击任何内容,

dispatch_async(dispatch_get_main_queue(), ^{

});

还试过

[self performSelectorInBackground:@selector(loadDataThatToBeFetchedInThread:) 
                      withObject:objectArrayThatNeedToFetchData];
如果我在活动之间移动,这个似乎就停止了。尝试将其移动到AppDelegate方法但是当我尝试保存到SQlite DB时,我得到了一些错误。难道我做错了什么?请有人帮忙。

提前致谢

3 个答案:

答案 0 :(得分:2)

好吧,dispatch_get_main_queue()将为您提供主题,因此可能不是您想要的。

相反,您应该使用以下方式获取后台队列:

dispatch_async (dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ ... });

然后,按惯例发送一些通知,甚至直接回调主线程(在UI中)报告成功:

dispatch_async (dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    // Do the download...
    // Download finishes...
    dispatch_async(dispatch_get_main_queue(), ^{
        // Call a UI-updating method, or similar
    });
});

答案 1 :(得分:2)

查找NSURLSessionNSURLSessionDownloadTask。这是Apple最新最好的。

2015 WWDC videos2014 WWDC videos观看核心网络视频(核心网络中的新功能)。

URL Session Programming Guide也是一个很好的资源。

NSURLSession是开箱即用的 - 这是您正在寻找的。

作为奖励NSURLSessionDownloadTask可让您在应用程序更改为后台状态(与后台线程有很大不同)时继续下载。它还允许您轻松取消和/或恢复下载。

答案 2 :(得分:1)

我建议使用AppConstant.CALL_ID = mCallId = getIntent().getStringExtra( SinchService.CALL_ID);//Contain Special characters. //And in onServiceConnected() use Call call = getSinchServiceInterface().getCall(mCallId); NSOperation来保持它的整洁。

阅读&观看更多:

这是一个基本设置,您可以自定义以满足您的需求

免责声明:虽然看起来很多,但它可以弥补更好的API。

首先,让我们定义一个接口来处理我们的API端点:

NSOperationQueue

接下来,让我们构建自定义// Endpoints.swift let api_base = "https://myserver.com/" let api_path = "api/" protocol EndpointGenerator { func URL() -> NSURL } extension EndpointGenerator { func URL() -> NSURL { return NSURL(string: api_base)! } } // Represents a null endpoint. It will fail. struct NullEndpoint: EndpointGenerator { } enum Endpoint: String, EndpointGenerator { case Login = "login" case SignUp = "signup" func URL() -> NSURL { return NSURL(string: api_base + api_path + self.rawValue)! } }

NSOperation

差不多完成了,让我们处理实际的队列:

// Operation.swift
public class Operation: NSOperation {
    public typealias Completion = Operation -> ()
    public typealias Error = NSError -> ()

    var endpoint: EndpointGenerator {
        return NullEndpoint()
    }

    var headerParams: [String:String]? {
        return nil
    }

    var requestBody: [String:AnyObject]? {
        return nil
    }

    var method: HTTPMethod {
        return .GET
    }

    var networkTask: NSURLSessionTask?

    var completion: Completion?
    var error: Error?
    public var parsedObject = [String:AnyObject]()

    override public init() { }

    public init(completion: Completion, error: Error) {
        self.completion = completion
        self.error = error
    }

    override public func start() {
        NSURLSessionImplementaion.execute(self)
    }

    override public func cancel() {
        networkTask?.cancel()
        networkTask = nil
    }
}

最后,下载部分:

// OperationQueue.swift
public class OperationQueue: NSOperationQueue {
        public static let internalQueue = OperationQueue()

        public static func addOperation(operation: NSOperation) {
            internalQueue.addOperation(operation)
        }

        public static func addOperations(operations: NSOperation...) {
            for operation in operations {
                addOperation(operation)
            }
        }

        public static func cancellAllOperations() {
            internalQueue.cancelAllOperations()
        }
}

你是如何实现的?假设您想要点击// NSURLSessionImplementation.swift enum HTTPMethod: String { case POST = "POST" case GET = "GET" case PATCH = "PATCH" } public let OSNetworkingErrorDomain = "com.swanros.errordomain" class NSURLSessionImplementaion { class func execute(operation: Operation) { let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration()) let request = NSMutableURLRequest(URL: operation.endpoint.URL()) if let headerParams = operation.headerParams { for element in headerParams { request.setValue(element.1, forHTTPHeaderField: element.0) } } if let body = operation.requestBody { do { request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(body, options: .PrettyPrinted) } catch { return } } request.HTTPMethod = operation.method.rawValue let task = session.dataTaskWithRequest(request) { data, response, error in if let e = error { operation.error?(e) return } guard let d = data else { operation.error?(errorWithDescription("No data")) return } do { let json = try NSJSONSerialization.JSONObjectWithData(d, options: .MutableLeaves) as? [String:AnyObject] guard let j = json else { operation.error?(errorWithDescription("Error parsing JSON.")) return } if let errorMessage = string(j, key: "error") { operation.error?(errorWithDescription(errorMessage)) return } operation.parsedObject = j operation.completion?(operation) } catch let jsonError as NSError { operation.error?(jsonError) } } operation.networkTask = task task.resume() } } func errorWithDescription(desc: String) -> NSError { return NSError(domain: OSNetworkingErrorDomain, code: 0, userInfo: [NSLocalizedDescriptionKey:desc]) } 端点。子类/login如下:

Operation

你这样使用它:

// LogInOperation.swift
public class LogInOperation: Operation {
    override var endpoint: EndpointGenerator {
        // A nice way to represent endpoints: use enums and protocols!
        return Endpoint.Login
    }

    // The headers for this particular request. Maybe you need a token here!
    override var headerParams: [String:String]? {
        return [
            "Content-Type": "application/json",
            "Application-Id": "bAAvLosWNeSTHrlYilysdeEYoJHUXs88"
        ]
    }

    // The HTTP request body!
    override var requestBody: [String:AnyObject]? {
        return [
            "mail": mail,
            "password": password
        ]
    }

    // .GET is default
    override var method: HTTPMethod {
        return .POST
    }

    private var mail: String
    private var password: String

    public init(mail m: String, password p: String, completion: Completion, error: Error) {
        mail = m
        password = p

        super.init(completion: completion, error: error)
    }
}