iOS 具有 dispatch_async/asynchronous 方法的单例 API 经理:这意味着什么?
iOS Singleton API manager with dispatch_async/asynchronous methods: what's the implication?
像这样用Singleton表示一个"API Manager"对象是典型的设计模式:-
class APIManager {
let ENDPOINT_URL = "http://remote-server-fqdn.com"
var storage : Storage!
var currentlyLoggedIn = false
class var sharedInstance: APIManager {
struct Static {
//---to contain the one and only instance of this class---
static var instance: APIManager!
//---a token to ensure that the class is only instantiated once---
static var token: dispatch_once_t = 0
}
//---executes a block object once and only once for the lifetime of an application---
dispatch_once(&Static.token) {
//---creates an instance of this class---
Static.instance = APIManager()
Static.instance.storage = Storage.sharedInstance
}
//---returns the instance of this class---
return Static.instance
}
这确保我们有一个 APIManager
对象,具有一致的标记,我们可以在 ViewController 或模型方法的不同部分使用它。问题不大,容易理解。
问题
但是,问题是 --- 如果我使用的是 Alamofire 或AFNetworking 作为方法进入我的 APIManager
class?
这些(异步)方法嵌套在我的 Singleton class 中是否会导致任何意外的性能问题或意外的副作用?
我知道 async
服务器 API 调用或 dispatch_async
方法将使用 GCD 并且仍然可以实现并发。
作为附加问题:这种并发是由单例的异步方法调用并发并行还是并发但不并行实现的?
比如像这样:-
class APIManager {
// .... same block of code as above for declaring dispatch_once above.
// additional code which are API server calls (and async by nature) here
func loginRequest(username : String, password : String, completion: (loginSuccess : Bool) -> Void) {
// Alamofire.request ...
}
func getRequest(...) {
// Alamofire.request ...
}
func postRequest(...) {
// Alamofire.request ...
}
func testAsync() {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
println("just do something asynchronously")
}
}
}
这里有几个有效的正交问题。第一个问题是安全的一次性初始化。您似乎可以控制它 (dispatch_once
)。下一个问题是使用单例来抽象出外部依赖。太棒了——它可以帮助测试、后期迁移、重构等。看起来你已经控制住了它,除非我遗漏了某些部分,否则你应该让那部分保持简单 "thin"尽可能。
然后您似乎在问是否应该在相同的 API-抽象 class 中构建更复杂的操作,我想答案可能是 "no."为此制作其他 class(es)。听起来那里可能还存在一些重要的并发问题(即共享状态),但一如既往,没有灵丹妙药——你只需要自己解决这些问题。
处理共享状态的一种常见模式是拥有一个私有调度队列,并让所有读取或写入共享状态的操作分别使用 dispatch_sync
和 dispatch_barrier_sync
进行。但这只是一个简单的样板模式,用于在并发编程环境中管理共享状态(即防止不同的线程相互干扰 reads/writes);它对 API/App-specific 相互依赖关系没有任何作用(例如,如果您想延迟所有其他 API 调用,而初始 login/registration 调用仍在等待回复。)后者是您可以拥有的自己写。
像这样用Singleton表示一个"API Manager"对象是典型的设计模式:-
class APIManager {
let ENDPOINT_URL = "http://remote-server-fqdn.com"
var storage : Storage!
var currentlyLoggedIn = false
class var sharedInstance: APIManager {
struct Static {
//---to contain the one and only instance of this class---
static var instance: APIManager!
//---a token to ensure that the class is only instantiated once---
static var token: dispatch_once_t = 0
}
//---executes a block object once and only once for the lifetime of an application---
dispatch_once(&Static.token) {
//---creates an instance of this class---
Static.instance = APIManager()
Static.instance.storage = Storage.sharedInstance
}
//---returns the instance of this class---
return Static.instance
}
这确保我们有一个 APIManager
对象,具有一致的标记,我们可以在 ViewController 或模型方法的不同部分使用它。问题不大,容易理解。
问题
但是,问题是 --- 如果我使用的是 Alamofire 或AFNetworking 作为方法进入我的 APIManager
class?
这些(异步)方法嵌套在我的 Singleton class 中是否会导致任何意外的性能问题或意外的副作用?
我知道 async
服务器 API 调用或 dispatch_async
方法将使用 GCD 并且仍然可以实现并发。
作为附加问题:这种并发是由单例的异步方法调用并发并行还是并发但不并行实现的?
比如像这样:-
class APIManager {
// .... same block of code as above for declaring dispatch_once above.
// additional code which are API server calls (and async by nature) here
func loginRequest(username : String, password : String, completion: (loginSuccess : Bool) -> Void) {
// Alamofire.request ...
}
func getRequest(...) {
// Alamofire.request ...
}
func postRequest(...) {
// Alamofire.request ...
}
func testAsync() {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
println("just do something asynchronously")
}
}
}
这里有几个有效的正交问题。第一个问题是安全的一次性初始化。您似乎可以控制它 (dispatch_once
)。下一个问题是使用单例来抽象出外部依赖。太棒了——它可以帮助测试、后期迁移、重构等。看起来你已经控制住了它,除非我遗漏了某些部分,否则你应该让那部分保持简单 "thin"尽可能。
然后您似乎在问是否应该在相同的 API-抽象 class 中构建更复杂的操作,我想答案可能是 "no."为此制作其他 class(es)。听起来那里可能还存在一些重要的并发问题(即共享状态),但一如既往,没有灵丹妙药——你只需要自己解决这些问题。
处理共享状态的一种常见模式是拥有一个私有调度队列,并让所有读取或写入共享状态的操作分别使用 dispatch_sync
和 dispatch_barrier_sync
进行。但这只是一个简单的样板模式,用于在并发编程环境中管理共享状态(即防止不同的线程相互干扰 reads/writes);它对 API/App-specific 相互依赖关系没有任何作用(例如,如果您想延迟所有其他 API 调用,而初始 login/registration 调用仍在等待回复。)后者是您可以拥有的自己写。