CNContactStore.requestAccessForEntityType argument issue - swift

I am trying to get authorisation to use the addressbook using the CNContactStore function requestAccessForEntityType but I get an error I don't understand.
The function is defined in the class as:
public func requestAccessForEntityType(entityType: CNEntityType, completionHandler: (Bool, NSError?) -> Void)
This is my code:
let addressBookRef: CNContactStore = CNContactStore.requestAccessForEntityType(CNEntityType.Contacts, completionHandler: authorizationHandler)
func authorizationHandler(granted: Bool, error: NSError?) {
}
Compiler error:
Extra argument 'completionHandler' in call

Turns out that I was defining the property directly in the class. Obviously you can't run a function there and so it was not working. Duh!
All I need to do was put in the class:
let addressBookRef = CNContactStore()
And the following when it was time to actually ask for permission:
addressBookRef.requestAccessForEntityType(CNEntityType.Contacts, completionHandler: authorizationHandler)

Related

Can't infer generic type on static function with completion block

I have a static function that uses generics, but I can't get it to infer the generic type when it's called. The function:
static func getDocument<T: JSONDecodable>(_ document: String, fromCollection collection: FirebaseStorage.FirestoreCollections, completion: #escaping (_ decodedDoc: T?, _ error: Error?) -> ()) {
let docRef = firestore.collection(collection.rawValue).document(document)
docRef.getDocument { documentSnapshot, error in
guard error == nil,
let docData = documentSnapshot?.data(),
let decodedDoc = T(json: docData) else {
completion(nil, error)
return
}
completion(decodedDoc, nil)
}
}
Called using:
FirebaseClient.getDocument(
id,
fromCollection: FirebaseStorage.FirestoreCollections.users) { (profile, error) in
}
This gives the error: Generic parameter 'T' could not be inferred. How can I make the generic part of the function work?
FirebaseClient.getDocument(
id,
fromCollection: FirebaseStorage.FirestoreCollections.users) { (profile: ProfileType?, error) in
}
You'll need to let Swift know what type profile is where I've added ProfileType. That should do it!
Kane's answer is good, but a more flexible approach is to pass the type directly. For example, this makes it possible to have an optional completion handler, or to ignore the parameter with _ if you don't care about it. (That said, this approach is a little longer to type, so sometimes Kane's way is better.)
static func getDocument<T: JSONDecodable>(_ document: String,
ofType: T.Type,
completion: #escaping (_ decodedDoc: T?, _ error: Error?) -> ())
This makes everything explicit. You call it this way:
FirebaseClient.getDocument(id, ofType: ProfileType.self) { (profile, error) in ... }
Note that there's no need to use the ofType parameter for anything. It's just there to specialize the generic.
This is pretty close to how Decodable works, and is applicable to a lot of problems. But Kane's solution is also handy at times if it's more convenient.

how to fix "forced cast" with xyz "only unwraps and bridges" in xCode and Swift

I see this error in the Analyze output for an app we are taking over:
/Users/bonnie/dev/elappa/Classes/FLAppGateway.swift:27:40: Forced cast from 'Error?' to 'NSError' only unwraps and bridges; did you mean to use '!' with 'as'?
The associated code block is like:
func fetchCountryCodes(_ completion: GetCountryCodesCompletion?)
{
let parameters = parametersToFetchCountryCodes()
serverManager?.postRequest(toURN: kGetCountryCallingCodes,
parameters: parameters,
domain: kUBPublicContentDomain,
success: { (object) in
self.handleGetCountryCodesSuccess(forObject: object as AnyObject?, completion: completion)
}) { (object, error) in
completion?(.failure(error as! NSError))
}
}
I am new to Swift. I read about Optionals and understand this is some issue with doing a forced class cast (using "as!") but not sure what. Any ideas?
elsewhere I see this code:
typealias GetCountryCodesCompletion = (Result<CountryCodes?, NSError>) -> ()
protocol AppGateway
{
func fetchCountryCodes(_ completion: GetCountryCodesCompletion?)
func marketingContents(completion: ((Result<[MarketingContent], NSError>) -> ())?)
}
Any ideas how to fix this Analyze/compiler warning?
This error happens because you are force casting using as! from a swift style Error to objective-c style NSError and this cannot be done.
So if you really need NSError, simple create one from your Error object by filling in the follow code
let objcError = NSError(domain: "somedomain", code: 123, userInfo: [:])
And then
completion?(.failure(objcError))

Swift 3 / How to solve: "Ambiguous use of 'authorize(_:completion:)'"

Please don't close because of duplicate of "Ambiguous use of...". Even with intense research I was not able to find any similar threads solving my issue.
I'm updating a project to Swift 3 and am stuck at a compiler error:
Ambiguous use of 'authorize(_:completion:)'
Code:
func connectToInstagram() {
let auth: NSMutableDictionary = ["client_id": INSTAGRAM_CLIENT_ID,
SimpleAuthRedirectURIKey: INSTAGRAM_REDIRECT_URI]
SimpleAuth.configuration()["instagram"] = auth
SimpleAuth.authorize("instagram") { (anyObject, error) in // error here
if anyObject != nil {...
SimpleAuth is a Framework to handle Social Media authentication written in Objective C.
SimpleAuth:
open class SimpleAuth : NSObject {
open class func authorize(_ provider: String!, completion: SimpleAuth.SimpleAuthRequestHandler!)
SimpleAuthRequestHandler:
public typealias SimpleAuthRequestHandler = (Any?, Error?) -> Swift.Void
public let SimpleAuthPresentInterfaceBlockKey: String
public let SimpleAuthDismissInterfaceBlockKey: String
I have tried to change the line to:
_ = SimpleAuth.authorize("instagram") { (anyObject: Any?, error: Error?) in
_ = SimpleAuth.authorize("instagram", completion: { (anyObject: Any?, error: Error?) in
But just as expected, it didn't changed anything. What am I missing? Help is very appreciated.
Build Log:
xy/InstagramVC.swift:409:9: error: ambiguous use of 'authorize(_:completion:)'
SimpleAuth.authorize("instagram") { (any: Any?, error: Error?) -> Swift.Void in
^
SimpleAuth.SimpleAuth:24:21: note: found this candidate
open class func authorize(_ provider: String!, completion: SimpleAuth.SimpleAuthRequestHandler!)
^
SimpleAuth.SimpleAuth:34:21: note: found this candidate
open class func authorize(_ provider: String!, options: [AnyHashable : Any]! = [:], completion: SimpleAuth.SimpleAuthRequestHandler!)
The problem is with the API. They provide these two functions:
open class func authorize(_ provider: String!, completion: SimpleAuth.SimpleAuthRequestHandler!)
and
open class func authorize(_ provider: String!, options: [AnyHashable : Any]! = [:], completion: SimpleAuth.SimpleAuthRequestHandler!)
but as you can see the options argument of the second function has been given a default argument ([:]). So when you don't specify the options parameter, the compiler can't tell which function you want to call.
This means the first function can't be used. You'll always have to use the second function and pass an explicit options argument. So:
authorize("instagram", options: [:]) { (any: Any?, error: Error?) -> Void in ... }
It's probably worth filing a bug with the SimpleAuth framework author(s).

Passing closure in Swift

I have a function that I've been using in my code, but I need to pass a completion handler to it now (so I can exit a dispatch_group). I didn't want it to effect the rest of my code so I tried changing the namespace from this:
func uploadRecordable<T: Recordable>(instanceConformingToRecordable: T, database: CKDatabase)
to this:
func uploadRecordable<T: Recordable>(instanceConformingToRecordable: T, database: CKDatabase, completionHandler: (())? = nil)
When I go to pass a closure to it like so:
cloud.uploadRecordable(testRecordable, database: database) {
dispatch_group_leave(forCloudToBeClearOfTestRecord)
}
I get this error:
Function produces expected type 'Void' (aka '()'); did you mean to call it with '()'?
I think that because the completionHandler: (())? argument has a default value of nil the compiler is confused by the closure, but when I tried this I still get same error:
cloud.uploadRecordable(testRecordable, database: database, completionHandler: {
dispatch_group_leave(forCloudToBeClearOfTestRecord)
})
I haven't passed a lot of closures, so I could be doing it wrong, but (())? has worked for me in the past... Also, if it makes any difference this is being called in my tests not my regular code.
Any help on what I'm missing here?
-EDIT-
After changing the closure argument to (() -> ())? I get this error:
Cannot invoke `uploadRecordable` with an argument list of type '(MockRecordable?, database: CKDatabase, completionHandler: (() -> ())?)'
The first two arguments have been working fine, but it doesn't like my closure still. Should I be putting something on the first line (e.g. var in) even though I'm not giving it any variables. Thanks in advance.
In the function declaration, rather than declaring the parameter as completionHandler: (())?, you want completionHandler: (() -> Void)? or completionHandler: (() -> ())?.
Thus:
func uploadRecordable<T: Recordable>(instanceConformingToRecordable: T, database: CKDatabase, completionHandler: (() -> Void)? = nil) { ... }
Or
func uploadRecordable<T: Recordable>(instanceConformingToRecordable: T, database: CKDatabase, completionHandler: (() -> ())? = nil) { ... }

The meaning of urlSession.dataTaskWithRequest(request)

When I read the book about swift in the Network Development chapter, I met some code which I cannot understand. The code is as follows:
let sessionTask = urlSession.dataTaskWithRequest(request) {
(data, response, error) in
handler(response, data)
}
the prototype of this function in swift is:
public func dataTaskWithRequest(request: NSURLRequest, completionHandler: (NSData?, NSURLResponse?, NSError?) -> Void) -> NSURLSessionDataTask
As you can see, the prototype has 2 parameters, one is request, another is completionHandler. But in the above code, it also has one parameter. And also I cannot understand the code in the curly braces, where do the 3 variable data, response, error come from? I cannot find any definition of the 3 variables. Who can help me understand the code, thanks in advance.
It is called a trailing closure, it's a cleaner way of passing a function to another function if that function is the last argument. The same code can be written as:
let sessionTask = NSURLSession.sharedSession()
let request = NSURLRequest()
sessionTask.dataTaskWithRequest(request, completionHandler: {(data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in
})
If you need to pass a closure expression to a function as the function’s final argument and the closure expression is long, it can be useful to write it as a trailing closure instead. A trailing closure is a closure expression that is written outside of (and after) the parentheses of the function call it supports
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html#//apple_ref/doc/uid/TP40014097-CH11-ID102
func aFunction(callback: (done: Bool) -> Void) {
let finished = true
callback(done: finished)
}
aFunction { (done) -> Void in
print("we are done \(done)")
}