Skip to content

Instantly share code, notes, and snippets.

@nixta
Last active August 29, 2015 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nixta/a5df128557fe61a27223 to your computer and use it in GitHub Desktop.
Save nixta/a5df128557fe61a27223 to your computer and use it in GitHub Desktop.
Translating a delegate model to a closures model. Put these files in the same Swift module.
//
// AGSQueryTask.swift
// swift-samples
//
// Created by Eric Ito on 7/28/14.
// Copyright (c) 2014 Esri. All rights reserved.
//
import ArcGIS
// workaround for accessing closure wrapped in an enum
// https://devforums.apple.com/message/986308#986308
struct Container<T> {
var closure: T
}
// this enum will have our closure types
enum QueryCallbackType {
case ExecuteClosure(Container<(featureSet: AGSFeatureSet?, error: NSError?) -> ()>)
case ExecuteWithIDsClosure(Container<(objectIDs: [Int]?, error: NSError?) -> ()>)
case ExecuteWithRelatedFeaturesClosure(Container<(relatedFeatures: [Int:[AGSFeatureSet]]?, error: NSError?) -> ()>)
case ExecuteFeatureCountClosure(Container<(featureCount: Int?, error: NSError?) -> ()>)
}
extension AGSQueryTask {
// create a private struct to hold our delegate handler
private struct Static {
static var instance: AGSQueryTaskDelegateHandler! = nil
static var token: dispatch_once_t = 0
}
var delegateHandler: AGSQueryTaskDelegateHandler! {
get {
dispatch_once(&Static.token) {
Static.instance = AGSQueryTaskDelegateHandler()
self.delegate = Static.instance
}
return Static.instance!
}
set {
Static.instance = newValue
self.delegate = Static.instance
}
}
public func executeQuery(query: AGSQuery, withCompletion completion: (featureSet: AGSFeatureSet?, error: NSError?) -> ()) -> NSOperation? {
let op = self.executeWithQuery(query)
return self.delegateHandler.registerCallback(.ExecuteClosure(Container(closure: completion)), forOperation: op)
}
public func executeForIDsWithQuery(query: AGSQuery, withCompletion completion:(objectIDs: [Int]?, error: NSError?) -> ()) -> NSOperation? {
let op = self.executeForIdsWithQuery(query)
return self.delegateHandler.registerCallback(.ExecuteWithIDsClosure(Container(closure: completion)), forOperation: op)
}
public func executeWithRelationshipQuery(query: AGSRelationshipQuery, withCompletion completion:(relatedFeatures: [Int: [AGSFeatureSet]]?, error: NSError?) -> ()) -> NSOperation? {
let op = self.executeWithRelationshipQuery(query)
return self.delegateHandler.registerCallback(.ExecuteWithRelatedFeaturesClosure(Container(closure: completion)), forOperation: op)
}
public func executeFeatureCountWithQuery(query: AGSQuery, withCompletion completion:(count: Int?, error: NSError?) -> ()) -> NSOperation? {
let op = self.executeFeatureCountWithQuery(query)
return self.delegateHandler.registerCallback(.ExecuteFeatureCountClosure(Container(closure: completion)), forOperation: op)
}
}
//
// AGSQueryTaskDelegateHandler.swift
// swift-samples
//
// Created by Eric Ito on 7/28/14.
// Copyright (c) 2014 Esri. All rights reserved.
//
import ArcGIS
private enum QueryResultsType {
case Execute((AGSFeatureSet?, NSError?))
case ExecuteWithIDs(([Int]?, NSError?))
case ExecuteWithRelatedFeatures(([Int:[AGSFeatureSet]]?, NSError?))
case ExecuteFeatureCount((Int?, NSError?))
}
// MARK: Internal Delegate Handler
internal class AGSQueryTaskDelegateHandler: NSObject, AGSQueryTaskDelegate {
// this will map our operation to our callback
private var callbacks: [Int:QueryCallbackType] = [Int:QueryCallbackType]()
internal func registerCallback(callback: QueryCallbackType, forOperation op: NSOperation) -> NSOperation {
self.callbacks[op.hash] = callback
return op
}
// MARK: AGSQueryTaskDelegate
// TODO: Why do we have to mark these delegate methods public??
public func queryTask(queryTask: AGSQueryTask!, operation op: NSOperation!, didExecuteWithFeatureSetResult featureSet: AGSFeatureSet!) {
unpackAndFireCallbackForOperation(op, resultType: .Execute((featureSet, nil)))
}
public func queryTask(queryTask: AGSQueryTask!, operation op: NSOperation!, didFailWithError error: NSError!) {
unpackAndFireCallbackForOperation(op, resultType: .Execute((nil, error)))
}
public func queryTask(queryTask: AGSQueryTask!, operation op: NSOperation!, didExecuteWithObjectIds objectIds: [AnyObject]!) {
unpackAndFireCallbackForOperation(op, resultType: .ExecuteWithIDs((objectIds as? [Int], nil)))
}
public func queryTask(queryTask: AGSQueryTask!, operation op: NSOperation!, didFailQueryForIdsWithError error: NSError!) {
unpackAndFireCallbackForOperation(op, resultType: .ExecuteWithIDs((nil, error)))
}
public func queryTask(queryTask: AGSQueryTask!, operation op: NSOperation!, didExecuteWithRelatedFeatures relatedFeatures: [NSObject : AnyObject]!) {
unpackAndFireCallbackForOperation(op, resultType: .ExecuteWithRelatedFeatures((relatedFeatures as? [Int:[AGSFeatureSet]], nil)))
}
public func queryTask(queryTask: AGSQueryTask!, operation op: NSOperation!, didFailRelationshipQueryWithError error: NSError!) {
unpackAndFireCallbackForOperation(op, resultType: .ExecuteWithRelatedFeatures((nil, error)))
}
public func queryTask(queryTask: AGSQueryTask!, operation op: NSOperation!, didExecuteWithFeatureCount count: Int) {
unpackAndFireCallbackForOperation(op, resultType: .ExecuteFeatureCount((count, nil)))
}
public func queryTask(queryTask: AGSQueryTask!, operation op: NSOperation!, didFailQueryFeatureCountWithError error: NSError!) {
unpackAndFireCallbackForOperation(op, resultType: .ExecuteFeatureCount((nil, error)))
}
// MARK: Private
private func unpackAndFireCallbackForOperation(operation: NSOperation, resultType: QueryResultsType) {
switch resultType {
case .Execute(let (featureSet, error)):
fireCallbackForOperation(operation, values: (featureSet, error))
case .ExecuteWithIDs(let (objectIDs, error)):
fireCallbackForOperation(operation, values: (objectIDs, error))
case .ExecuteWithRelatedFeatures(let (relatedFeatures, error)):
fireCallbackForOperation(operation, values: (relatedFeatures, error))
case .ExecuteFeatureCount(let (count, error)):
fireCallbackForOperation(operation, values: (count, error))
}
}
private func fireCallbackForOperation(operation: NSOperation, values: (Any?, Any?)) {
if let callbackType = self.callbacks[operation.hash] as? QueryCallbackType {
switch callbackType {
case .ExecuteClosure(let container):
let (featureSet, error) = values
container.closure(featureSet: featureSet as? AGSFeatureSet, error: error as? NSError)
case .ExecuteWithIDsClosure(let container):
let (objectIDs, error) = values
container.closure(objectIDs: objectIDs as? [Int], error: error as? NSError)
case .ExecuteWithRelatedFeaturesClosure(let container):
container.closure(relatedFeatures: values.0 as? [Int:[AGSFeatureSet]], error: values.1 as? NSError)
case .ExecuteFeatureCountClosure(let container):
container.closure(featureCount: values.0 as? Int, error: values.1 as? NSError)
}
self.callbacks[operation.hash] = nil
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment