I am trying to assign a delegate to uber ios widget RideRequestButton.
class UberRideRequestButtonDelegate:RideRequestButtonDelegate{
func rideRequestViewController(rideRequestViewController: RideRequestViewController, didReceiveError error: NSError) {
let errorType = RideRequestViewErrorType(rawValue: error.code) ?? .Unknown
print("errorType\(errorType)")
}
func rideRequestButton(button: RideRequestButton, didReceiveError error: RidesError){
}
}
I am getting the error - "Type UberRideRequestButtonDelegate does not confirm to protocol RideRequestButtonDelegate"
The error message usually includes additional information about which methods are missing. Can you provide the full error? You are likely missing those methods.
Related
I have a function:
func logLocalisedDescription(_ error: Any) {
NSLog(error.localizedDescription)
}
I want this to work for NSError and SKError, both of which have a localizedDescription, but no common superclass or protocol that declares it.
Is there a way to tell the Swift compiler to do run-time rather than compile-time type checking, like Objective-C's id? I tried Any, AnyObject and AnyClass, but none of them worked.
I'm fine with the code failing at runtime if the property doesn't exist.
Please don't suggest retrofitting classes to adopt protocols or other solutions. I'm aware of those. The question is about how to do dynamic typing in Swift.
Use a protocol :)
protocol LocalizedDescribable {
var localizedDescription: String { get }
}
extension NSError: LocalizedDescribable {}
extension SKError: LocalizedDescribable {}
func logLocalizedDescription(_ error: LocalizedDescribable) {
NSLog(error.localizedDescription)
}
You're asking about sending arbitrary Objective-C messages to an object of unknown type. I would call that dynamic messaging rather than dynamic type checking. In Objective-C, there are ways to make any object handle any message, regardless of the object's type.
Swift (on Apple platforms) allows you to do Objective-C-style dynamic messaging to AnyObject, as documented under “Accessing Objective-C Methods and Properties” in the AnyObject reference. In this case, here's the syntax:
func logLocalizedDescription(_ error: Any) {
if let d = (error as AnyObject).localizedDescription as String? {
NSLog("%#", d)
}
}
I had to explicitly specify the type of the message here to avoid an “Ambigious use of 'localizedDescription'” error, because there are multiple definitions of localizedDescription with different types (most are String, but Progress.localizedDescription is String!).
However, you don't need to use dynamic messaging in this particular case. The preferred Swift way, in this case, is to use as? Error, like this:
func logLocalizedDescription(_ error: Any) {
if let error = error as? Error {
NSLog("%#", error.localizedDescription)
} else {
NSLog("unknown error: %#", String(describing: error))
}
}
As it happens, SKError already conforms to Error, although it's not documented to do so. The above function will print an SKError's localizedDescription.
If you don't want to rely on this undocumented conformance, you can explicitly make it conform:
extension SKError: Error { }
Since Error declares localizedDescription, and SKError already implements localizedDescription, this retroactive conformance requires no implementation of its own.
Note also that it's inappropriate to pass an unknown string (like an error's localizedDescription) as the first argument of NSLog, because the first argument of NSLog is a format string. If the string contains unexpected % characters, the runtime behavior is undefined.
Let me prefix with why I think this is not a duplicate of How to provide a localized description with an Error type in Swift?
The answers provided will still result in some static/class function call and not an initializer style or require casting to NSError (which I like to avoid).
A brief summery of the reasons:
A Swift function that throws does not declare the error type. We cannot enforce the catch to pass a custom type that simply conforms to the Error protocol. Knowing that, on the do-catch side, we get no help from the compiler as to what type (if custom) of error we get and by default we'll expect the known NSError properties. Otherwise, we need to simply rely on textual documentations explaining the type of errors we can catch, as the catch will simply pass an Error type.
Now, unlike NSError, Error is a protocol where the properties we get in userInfo are read only. So we resort to constructing an NSError type, and casting it as Error.
I am trying to create a simple clean struct that return an Error type (not NSError) where I can throw like:
throw MYError(domain: "com.somthing.error", code: 0, userInfo: [NSLocalizedDescriptionKey : "Something bad happened"])
Main issue is that the only way to set the NSLocalizedDescriptionKey, is by initializing an NSError object. Doing so will require casting to Error type (which is something I'm trying to avoid).
I first tried to use extension Error {..., but cannot use an initializer.
If I use a struct conforming to Error protocol (struct MyError: Error {...), I still have the problem of localizedDescription is get only.
What I use is actually something like:
struct MYError: Error {
static func with(domain: String = "com.somthing.error", code: Int = 0, localizedDescription: String) -> Error {
return NSError(domain: domain, code: code, userInfo: [NSLocalizedDescriptionKey : localizedDescription]) as Error
}
}
Which I can use like:
throw MYError.with(localizedDescription: "Some Error has happened")
Intuitively, I would expect a type like MYError to just use an initializer MYError(domain:..., not a static function.
The more Swifty way would be something like:
enum ErrorType: Error {
case one
case two
case three(with: String)
}
...
// In some function:
throw ErrorThrown.three(with: "Three!")
...
// Catch like:
catch ErrorType.three(let str) {
print("Error three: \(str)")
}
It is not clear if we're there yet. It seems that NSError is still much at play where I know I can expect to get a localizedDescription an optional localizedFailureReason and the familiar NSError properties.
Similarly as in How to provide a localized description with an Error type in Swift?
you can define a custom error type adopting the LocalizedError
protocol:
public struct MyError: Error {
let msg: String
}
extension MyError: LocalizedError {
public var errorDescription: String? {
return NSLocalizedString(msg, comment: "")
}
}
Example:
do {
throw MyError(msg: "Something happened")
} catch let error {
print(error.localizedDescription)
}
This prints the localized version of the given message.
Note that error in the catch-clause is a general Error, so
the caller does not need to cast it to the concrete error type (or even know
which error type is thrown).
Error is a protocol, you can throw anything which conforms to that protocol
For example
struct MYError : Error {
let description : String
let domain : String
var localizedDescription: String {
return NSLocalizedString(description, comment: "")
}
}
And you can use it:
func test() throws
{
throw MYError(description: "Some Error has happened", domain: "com.somthing.error")
}
do {
try test()
} catch let error as MYError{
print("error: ", error.domain, error.localizedDescription)
}
Finally found a way to stick anything in a generic Error type.
Thanks to vadian and Martin R, on which answers I finally came to this part.
Comes down to this:
struct MyError: Error {
var locString: String
var reason: String?
var code: Int
var wish: String
}
// The errorDescription is the only part that actually comes generically with Error
extension MyError: LocalizedError {
// This is actually part of LocalizedError
var errorDescription: String? {
return locString
}
}
extension Error {
var errorCode: Int {
return (self as! MyError).code
}
var failureReason: String? {
return (self as! MyError).reason
}
var everythingYouWishFor: String {
return (self as! MyError).wish
}
}
...
throw MyError(locString: "Localized string", reason: "The reason", code: 12, wish: "Best wishes")
This question already has answers here:
How to provide a localized description with an Error type in Swift?
(7 answers)
Closed 6 years ago.
I've an error class that is:
public enum ModelError: Error {
case invalidArray(model: String)
var localizedDescription: String {
switch self {
case .invalidArray(model: let model):
return "\(model) has an invalid array"
default:
return "modelError"
}
}
}
and when passed as an Error in a callback function, I want to access its custom localizedDescription. For instance:
func report(_ error: Error) {
print("Error report: \(error.localizedDescription)")
}
But calling report(ModelError.invalidArray(model: "test")) prints:
"The operation couldn’t be completed. (ModelError error 0.)"
Such things seems feasible with NSError since I can override the localizedDescription property there. But I don't want to use NSError since it's not really a swift thing and a lot of libraries work with Error.
According to the Documentation, localizedDescription is implemented in a protocol extension, not in the protocol declaration, which means there's nothing to adhere to or override. There is a type-wide interface for enums that adhere to Error.
My way I get around this is to use a wrapper protocol:
protocol LocalizedDescriptionError: Error {
var localizedDescription: String { get }
}
public enum ModelError: LocalizedDescriptionError {
case invalidArray(model: String)
var localizedDescription: String {
switch self {
case .invalidArray(model: let model):
return "\(model) has an invalid array"
default:
return "modelError"
}
}
}
let error: LocalizedDescriptionError = ModelError.invalidArray(model: "Model")
let text = error.localizedDescription // Model Has an invalid array
I have the Swift code below.
func beanManager(_ beanManager: PTDBeanManager!, didDiscover bean: PTDBean!, error: Error!) {
if (bean.name == "SOME_NAME") {
connectToBean(bean!)
bean.delegate = self
print("Connected to Bean")
} else {
print("Found a Bean not named SOME_NAME")
}
}
func connectToBean(_ bean: PTDBean) {
var error: NSError?
deviceManager.connect(to: bean, error: &error)
bean.delegate = self
}
Xcode is giving me an error
Ambiguous use of 'connectToBean(_:error:)'
Not sure what is causing this.
The method (SDK written in Obj-C) being called is:
-(void)connectToBean:(PTDBean*)bean error:(NSError**)error;
The method signature shown during auto-completion in Xcode is:
deviceManager?.connect(to: PTDBean!, error:NSErrorPointer)
There are no NSErrorPointer parameters any more. Use try instead:
do {
try deviceManager?.connect(to: bean)
} catch {
// whatever
}
After reading the Apple docs on optional protocol requirements it says you can use optional chaining to check for the implementation. I tried this out and I keep getting an error. It seems like this is no longer a valid way of doing this and I am trying to find out if there is a new way to do this now.
Here is a example so you can see the error: http://swiftstub.com/743693493/
Here is my code:
#objc protocol Bearable {
func growl()
optional func cough() -> String //Apparently bears cough when they are scared.
}
#objc class Bear:Bearable {
var name = "Black Bear"
func growl() {
println("Growllll!!!")
}
}
#objc class Forest {
var bear:Bear?
func scareBears() {
if let cough = bear?.cough?() {
println(cough)
} else {
println("bear was scared")
}
}
}
I get the error: error: 'Bear' does not have a member named 'cough'
if let cough = bear?.cough?() {
The error you're getting makes sense because Swift can know at compile time that Bear doesn't implement cough() (whereas Objective-C wouldn't necessarily be able to know that).
To make your code compile, you need to define bear using the Bearable protocol instead of the Bear class.
var bear: Bearable?
Which is probably what you'd want anyway. Otherwise, there's not much point in creating that protocol.