我有一个应用程序需要在用户登录时下载大量数据。我想将其下载部分移动到后台线程,以便用户可以导航应用程序而无需等待下载完成。我尝试了以下方法,但其中一些仍然锁定了应用程序,因此用户无法点击任何内容,
dispatch_async(dispatch_get_main_queue(), ^{
});
还试过
[self performSelectorInBackground:@selector(loadDataThatToBeFetchedInThread:)
withObject:objectArrayThatNeedToFetchData];
如果我在活动之间移动,这个似乎就停止了。尝试将其移动到AppDelegate方法但是当我尝试保存到SQlite DB时,我得到了一些错误。难道我做错了什么?请有人帮忙。
提前致谢
答案 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)
查找NSURLSession和NSURLSessionDownloadTask。这是Apple最新最好的。
从2015 WWDC videos和2014 WWDC videos观看核心网络视频(核心网络中的新功能)。
URL Session Programming Guide也是一个很好的资源。
NSURLSession是开箱即用的 - 这是您正在寻找的。 p>
作为奖励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)
}
}