I work with Xcode 7 with swift and I would use the Touch Id. Only I have a error when I use canEvaluatePolicy. I understand my error, I call an argument too. Only if I do not call, it makes me a error because I did not manage my error ...
Here are my error and my code:
PS: sorry for my bad English.
Error : Extra argument 'error' in call
or
Error : Call can throw, but it is not marked with 'try' and the error is not handled
My code :
import Foundation
import UIKit
import LocalAuthentication
class touchid : UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var lblTouchId: UILabel!
override func viewDidLoad() {
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
#IBAction func authenticateWithTouchID(sender: AnyObject) {
let authenticationObject = LAContext()
self.pleaseWait()
if authenticationObject.canEvaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics) {
authenticationObject.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: "Access", reply: {(Bool, authenticationError) in
if authenticationError != nil {
// Authentification annulé ou Touch id non disponible
self.lblTouchId.text = "annulé ou touch id non disponible"
self.clearAllNotice()
self.errorNotice("Erreur !")
}
else {
if Bool == true {
self.lblTouchId.text = "authentification réussi"
self.clearAllNotice()
self.successNotice("Succès !")
}
else {
self.lblTouchId.text = "echec de l'authentification"
self.clearAllNotice()
self.errorNotice("Erreur !")
}
}
}
)
}
}
}
As mentioned in Using Swift with Cocoa and Objective-C, all Objective-C methods that use NSError to return an error object will now throw when called from Swift 2.0, so you need to use:
do {
try method()
} catch let error as NSError {
reportError(error)
}
Removing the reference to NSError in the method() call.
Looking at Apple's documentation, something seems off. The method signature is:
func canEvaluatePolicy(_ policy: LAPolicy, error error: NSErrorPointer) -> Bool
The odd part is that currently, the method doesn't throw anything, so putting it in a do-try block isn't necessary. I don't know if (but my guess is that yes) this framework is still getting tweaked with Swift 2.0, but I thought I remembered it implementing throw at one point in the Xcode/Swift beta iterations. At one point the compiler was acting a little wonky and said that:
1 - the method signature only had 1 parameter, but implements throws (which it doesn't)
2 - But as mentioned above, when you do that, the compiler then gives you different errors.
One thing to point out is that the current method signature, as of this writing, has a second parameter which is an NSErrorPointer, not an NSError? object. Treat it like the current Apple docs suggest, so add something like:
var error: NSErrorPointer?
let canEvaluatePolicty = LAContext().canEvaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics, error: error!)
And your code should compile. It might be a good idea to keep an eye on this framework as more iterations of the beta's come out.
Good Luck!
Although the answer from g_blott does indeed compile, it's not good practice to force unwrap when you're not sure what could happen.
This code also compiles, but doesn't force unwrap anything and handles the existence of an error:
var error: NSError?
let errorPointer: NSErrorPointer = NSErrorPointer(&error)
let canEvaluate = context.canEvaluatePolicy(.deviceOwnerAuthentication, error: errorPointer)
if let error = error {
print("Oh noes, an error! ", error)
} else if canEvaluate {
print("Can evaluate")
} else {
print("Can't evaluate")
}
Related
I'm new in iOS development, so maybe I'm thinking in the wrong way. I coded a view model with a function that calls an API, and everything works fine.
class SearchCityViewModel : ViewModelProtocol {
//OBSERVABLES
var cities = PublishSubject<[City]>()
var networkError = PublishSubject<Void>()
var generalError = PublishSubject<Void>()
init(){
print("Init SearchCityViewModel")
reinit()
}
func reinit(){}
func searchCity(stringToSearch: String){
async {
do {
if stringToSearch.count>=2 {
let cities = try await(api.getCities(cityToSearch: stringToSearch)).payload!
self.cities.onNext(cities)
}
else {
self.cities.onNext([])
}
}
catch {
self.generalError.onNext(Void())
}
}
}
Now I want to handle errors. In the catch block I want to distinguish all the errors I want to handle gracefully, and for the other ones I just want to emit a general error. To do that, firstly I need to know which error is thrown when the situation I want to handle occurs. I usually do this with the debugger. For instance, I disable the internet connection, and i create a breakpoint inside the catch block. The idea is to check which error is thrown when the internet connection is disabled, in order to create a catch block for that kind of error.
Image of the debugger
I'm struggling because with the debugger I only see that is an AFError instance, but it's not telling me nothing more that can help me to catch it.
What is wrong with my workflow? Do I really need to read all the docs every time? For each library I use?
Thank you!
Perhaps you can read the articles and then you will know how to do it better, you can use the framework -oslog instead of using print function.
debugging your logging info
I found the way. What I was missing is casting the error as NSError. In this way, with the debugger is possible to see the domain and the code of the error. In the case of Alamofire, the real error is wrapped, and it's accessible through the underlyingError attribute. Once I had the domain and the code of the error, I wrote the following code:
class SearchCityViewModel : ViewModelProtocol {
//OBSERVABLES
var cities = PublishSubject<[City]>()
var networkError = PublishSubject<Void>()
var generalError = PublishSubject<Void>()
init(){
print("Init SearchCityViewModel")
reinit()
}
func reinit(){}
func searchCity(stringToSearch: String){
async {
do {
if stringToSearch.count>=2 {
let cities = try await(api.getCities(cityToSearch: stringToSearch)).payload!
self.cities.onNext(cities)
}
else {
self.cities.onNext([])
}
}
catch {
if let afError = asAFError, let underlyingError = afError.underlyingError as NSError?, underlyingError.domain == NSURLErrorDomain, underlyingError.code == NSURLErrorNotConnectedToInternet || underlyingError.code == NSURLErrorTimedOut {
self.networkError.onNext(Void())
}
else {
self.generalError.onNext(Void())
}
}
}
}
I am using Parse and PFUser in a Swift iOS app, and find myself in a case where PFUser.current() does not do exactly what I want, due to synchronisation issues.
For that reason I am trying to use: PFUser.getCurrentUserInBackground().
I got started with the code below, inspired from what can be found here: https://github.com/BoltsFramework/Bolts-ObjC.
But this document probably being a bit outdated, it does not quite work.
let userCheckTask = PFUser.getCurrentUserInBackground()
userCheckTask.continueWith {
(task: BFTask!) -> BFTask<AnyObject> in
if task.isCancelled() { // Error-1.
// the save was cancelled.
} else if task.error != nil {
// the save failed.
} else {
// the object was saved successfully.
var object = task.result() as PFObject // Error-2.
}
}
The compiler gives me two errors, this one on the line marked "Error-1"
Cannot invoke 'isCancelled' with no arguments
And this other one on the line marked "Error-2"
Expression type 'PFUser?' is ambiguous without more context
I have no idea what kind of argument 'isCancelled' is expecting.
Does anyone know how to fix those?
let userCheckTask = PFUser.getCurrentUserInBackground()
userCheckTask.continueWith {
(task: BFTask) -> BFTask<AnyObject> in
if let e = task.error {
return BFTask(error: e)
} else {
return BFTask(result: task.result)
}
}
I used this method very much in Swift 1.2: NSURLConnection.sendSynchronousRequest(:_:_:_) but this is apparently deprecated in iOS9. It still works however but now it uses the new Swift 2.0 Error Handling and I don't know how I will get the error message if it fails, ex. if time runs out.
I know I have to put it into a do-catch and then say try before the metho but I dont know how to catch the error message.
do {
let data = try NSURLConnection.sendSynchronousRequest(request, returningResponse: nil)
return data
}
catch _ {
return nil
}
Before I used NSError and then its description property, but now I have no clue.
Use automatic error variable, and you can cast it to NSError if you wish:
catch {
let nsError = error as NSError
print(nsError.localizedDescription)
}
You can now throw any object inheriting ErrorType, and provide custom handling in the catch sentence. You can also cast the error to NSError to access localizedDescription for handling third party errors.
Casting an enum ErrorType will produce a NSError with domain equal to the enum name, code equal to the enum value and an auto-generated localizedDescription with the following format:
The operation couldn’t be completed. (DOMAIN error CODE.)
For example, the following code:
enum AwfulError: ErrorType {
case Bad
case Worse
case Terrible
}
func throwingFunction() throws {
throw AwfulError.Worse
}
do {
try throwingFunction()
}
catch AwfulError.Bad {
print("Bad error")
}
catch let error as NSError {
print(error.localizedDescription)
}
Will print
The operation couldn’t be completed. (AwfulError error 1.)
Despite the question title specifying Swift 2, this answer is for Swift 3.
As #redent84 points out, since Swift 2 an Error object may be a home-made one. Here's a method I wrote to analyze and print the default error object available in a "catch" statement that doesn't specify any specific error type:
// Method to print an unknown Error type object to the system output.
static func printCaughtError(_ unknownError : Error) {
let objectDescription = String(describing: unknownError)
let localizedDescription = unknownError.localizedDescription
if localizedDescription != "" {
if localizedDescription.contains(objectDescription) {
print(localizedDescription)
return
}
if !objectDescription.contains(localizedDescription) {
print(objectDescription + ": " + localizedDescription)
return
}
}
print(objectDescription)
}
Then you can call it like this:
catch {
printCaughtError(error)
}
How to get the error message that is inside userInfo:
let errorMessage = (error as NSError).userInfo["message"] as? String
I am coding in Swift and attempting to use the findObjects() function for the Parse iOS SDK. However, I can't seem to figure out what type of error is being thrown by Parse if this function call fails. I'm a novice in Swift so that may be my issue. I attempt to call the function in a do->catch block and use the try keyword on the function call however I'm not sure what to catch. I can catch the error using the _ but I would like to grab the description from the error. Thanks!
P.S. I don't want to use the findObjectsInBackground() method.
do {
let object = try query.getFirstObject()
// do something with the object
} catch _ {
// this is where I would like to print out the error description
}
In Obj-C, which I assume will be similar, I print out the error.userInfo[#"error"] parameter of the NSError that is returned.
All you need is print(error). An example here:
func getReferenceNumberAsStringSync() -> String? {
let query = PFQuery(className: "PropertyCount")
do {
let object = try query.getFirstObject()
if let referenceNumber = object["count"] as? Int {
return String(referenceNumber)
}
} catch {
print(error)
}
return nil
}
I used this method very much in Swift 1.2: NSURLConnection.sendSynchronousRequest(:_:_:_) but this is apparently deprecated in iOS9. It still works however but now it uses the new Swift 2.0 Error Handling and I don't know how I will get the error message if it fails, ex. if time runs out.
I know I have to put it into a do-catch and then say try before the metho but I dont know how to catch the error message.
do {
let data = try NSURLConnection.sendSynchronousRequest(request, returningResponse: nil)
return data
}
catch _ {
return nil
}
Before I used NSError and then its description property, but now I have no clue.
Use automatic error variable, and you can cast it to NSError if you wish:
catch {
let nsError = error as NSError
print(nsError.localizedDescription)
}
You can now throw any object inheriting ErrorType, and provide custom handling in the catch sentence. You can also cast the error to NSError to access localizedDescription for handling third party errors.
Casting an enum ErrorType will produce a NSError with domain equal to the enum name, code equal to the enum value and an auto-generated localizedDescription with the following format:
The operation couldn’t be completed. (DOMAIN error CODE.)
For example, the following code:
enum AwfulError: ErrorType {
case Bad
case Worse
case Terrible
}
func throwingFunction() throws {
throw AwfulError.Worse
}
do {
try throwingFunction()
}
catch AwfulError.Bad {
print("Bad error")
}
catch let error as NSError {
print(error.localizedDescription)
}
Will print
The operation couldn’t be completed. (AwfulError error 1.)
Despite the question title specifying Swift 2, this answer is for Swift 3.
As #redent84 points out, since Swift 2 an Error object may be a home-made one. Here's a method I wrote to analyze and print the default error object available in a "catch" statement that doesn't specify any specific error type:
// Method to print an unknown Error type object to the system output.
static func printCaughtError(_ unknownError : Error) {
let objectDescription = String(describing: unknownError)
let localizedDescription = unknownError.localizedDescription
if localizedDescription != "" {
if localizedDescription.contains(objectDescription) {
print(localizedDescription)
return
}
if !objectDescription.contains(localizedDescription) {
print(objectDescription + ": " + localizedDescription)
return
}
}
print(objectDescription)
}
Then you can call it like this:
catch {
printCaughtError(error)
}
How to get the error message that is inside userInfo:
let errorMessage = (error as NSError).userInfo["message"] as? String