I see some methods throw out errors in Apple's Documentation. But I can't find any information about what it throws.
Like this methods below. It's in FileManager class.
func moveItem(at srcURL: URL, to dstURL: URL) throws
I want to know what kinds of errors it throws. Where can I get related information?
Unlike Java, where the throws declaration requires a type, in Swift you will not know, what type of Error will be thrown. The only thing you know is that the object conforms to the Error-protocol.
If you know that a function throws a certein Error (because it's well documented), you will need to cast the caught object properly.
Example:
do {
try moveItem(from: someUrl, to: otherUrl)
} catch {
//there will automatically be a local variable called "error" in this block
// let's assume, the function throws a MoveItemError (such information should be in the documentation)
if error is MoveItemError {
let moveError = error as! MoveItemError //since you've already checked that error is an MoveItemError, you can force-cast
} else {
//some other error. Without casting it, you can only use the properties and functions declared in the "Error"-protocol
}
}
Related
This part of code inside mono.flatMap(() -> ()) is giving me an error(or warning?) verifyClient.sms(request.phoneNumber(). Error is "Inappropriate blocking method call". I guess SMS call is a blocking call from a third party(TeleSign) sdk.
Error is shown in the picture.
#Override
public Mono<ResponseEntity<SuccessResponse>> postSms(
Mono<SendSmsDetail> sendSmsDetail, ServerWebExchange exchange) {
return sendSmsDetail.doOnNext(this::validate)
.flatMap(request -> {
try {
return Mono.just(verifyClient.sms(request.phoneNumber(),
buildSmsParam(request)));
} catch (Exception e) {
return Mono.error(new RuntimeException("Fail to verify", e));
}
})
.onErrorResume(this::defaultOrderErrorHandler);
}
Screenshot of the error:
Can someone please tell me how to resolve it? Just started using Reactor. By the way, if you notice the screenshot and the actual pasted code has differences on .flatMap(tlr -> tlr.) part. Code currently won't compile due to different return type. I am also trying to make it compile by returning Mono<ResponseEntity<SuccessResponse>>. That's what I am trying to do with the second flatMap. Change "tlr"(TeleSignResponse) to my own "SuccessResponse".
I may need a second post on how to make this compile.
TL;DR
I have a class with no public initializers or instances that passes an instance of itself to a closure in another class. It does this through a mirror of the other class. When I go to access that instance from within the closure, I'm getting a EXC_BAD_ACCESS error, but other parameters passed to the closure are clearly accessible and do not result in a bad access error. I have no idea why. See code below for replication in a new project or a playground.
Detailed Explanation
I've been trying to figure out a way to implement class-specific access control, where multiple specific classes have sole access to another class containing variables and functions to be shared between them. All other classes would not have such access. Kind of like a static class, or a Singleton pattern, but with specific, class-named access control.
I thought I had something that would actually work in pure swift, (which is nice for me since I don't know Objective-C, and only started on swift about 16 months ago.) It's done in an almost anti-swift manner, so just bear with me - my goal is to start with something functional and move it towards elegance and beauty from there.
Even though I'm reasonably confident it should all work, I'm encountering a EXC_BAD_ACCESS error in a very unexpected place.
The "class-specific private" class that you are not allowed to access an instance of unless you are on its "okay" list, we can call the Restricted class.
The class(es) that is(are) allowed access to the Restricted class we can call the Accessor class(es).
The programmer must tell the Restricted class to call a function from the Accessor, and "drop in" an instance of the Restricted class by passing it as a parameter to that function. You do this by passing in the name of the function to be called, an instance of the Accessor class on which to call said function, and any parameters that the function would need in addition to the Restricted class instance.
I could make an enormous switch in the Restricted class, each case of which properly calls each function indicated on each of the Accessor classes...but to get around that excessive overhead/setup, I have the name of the function to be called on the Accessor classes passed in as a string, and accessed through a mirror. Since mirrors only reflect properties and not functions, the function must be a property with an assigned closure, instead of a traditional function.
We can call these closures DropClosures, since their purpose is to have the shared, Restricted class dropped into them. In fact we could call this whole pattern the "DropClosure Pattern". (Or maybe anti-pattern, I know it's kind of gruesome as-is.)
The properties of the "shared" instance of the Restricted class are stored internally as a private static dict (as json, basically). To generate an actual instance of itself, the Restricted class uses a private initializer that accepts that dict as a parameter. After a DropClosure runs with said initialized instance, the Restricted class uses a Mirror of that instance to store any changes back in the "shared" dict, and the instance will go out of scope unless a reference is made to it. So after each DropClosure completes its run, the instance passed to it is more or less useless as a representation of the "shared" aspect of the class, intentionally so.
I only do this because there is no way to require that all references to a certain weak reference also be weak. I don't want a class with access to the weak reference to assign a strong reference to the same instance and keep it in memory, that would defeat the access control goal by allowing the instance to be shared outside of its access scope. Since I can't force the instance to expire once the closure has completed, the next best thing is to remove the motivation for doing so by making the object no longer connected to the shared source after the closure completes.
This all theoretically works, and will compile, and will not throw any swift exceptions when run.
The Accessor (or any class that has an instance of an Accessor) calls RestrictedClass.run(), the run code validates the Accessor instance, finds the DropClosure in that instance, and passes in an instance of the Restricted class to that closure.
However, whenever I try to access that instance from within the DropClosure, it gives me the aforementioned bad access error, seemingly on a C or Objective-C level.
As far as I can tell, the instance should be accessible at this point, and none of the variables being used should be dropping out of scope yet.
At this point I'm totally spitballing - is it possible that there is something in the background that prevents a class with no public initializers from being passed through a mirror? Does it have to do with passing it into a closure called from that mirror? Is there some kind of hidden weak reference that's making the instance get ARC'd?
Please note that I've tried discarding the "weak" wrapper object and only passing in the Restricted instance to the closure, and I get the same bad access error. The error is independent of the instance being weakly referenced.
Code:
import Foundation
typealias DropClosureVoid<T: AnyObject & AccessRestricted> = (_ weaklyConnectedInterface: WeaklyConnectedInterface<T>, _ usingParameters: Any?)->Void
typealias DropClosureAny<T: AnyObject & AccessRestricted> = (_ weaklyConnectedInterface: WeaklyConnectedInterface<T>, _ usingParameters: Any?)->Any?
enum AccessError : Error {
case InvalidFunction
case InvalidAccessClass
}
protocol AccessRestricted {
static func run<T:AnyObject>(_ closureName:String, in classObject: T, with parameters:Any?) throws
static func runAndReturn<T:AnyObject>(_ closureName:String, in classObject: T, with parameters:Any?) throws -> Any?
}
///This class contains an instance that should be expected to only temporarily represent the original, even if a strong reference is made that keeps the value in scope.
class WeaklyConnectedInterface<T:AnyObject> {
weak var value:T?
init(_ value: T) {
self.value = value
}
}
class Accessor {
let restrictedClassPassable:DropClosureVoid<RestrictedAccessClass> = { weaklyConnectedInterface, parameters in
print(weaklyConnectedInterface) // **EXC_BAD_ACCESS error here**
//note that the error above happens even if I pass in the instance directly, without the WeaklyConnectedInterface wrapper.
//It's clearly an issue that occurs when trying to access the instance, whether the instance is wrapped in a the class that makes a weak reference to it or not, which means that it is inaccessible even when strongly referenced.
if let parameterDict = parameters as? [String:String] {
print(parameterDict["paramkey"] ?? "nil")
print(weaklyConnectedInterface)
weaklyConnectedInterface.value?.restrictedVariable = "I've changed the restricted variable"
}
}
let anotherRestrictedClassPassable:DropClosureAny<RestrictedAccessClass> = { weaklyConnectedInterface, parameters in
if let parameterDict = parameters as? [String:String] {
print(parameterDict["paramkey"] ?? "nil")
print(weaklyConnectedInterface.value?.restrictedVariable as Any)
return weaklyConnectedInterface.value?.restrictedVariable
}
return nil
}
func runRestrictedClassPassable() throws {
let functionName = "restrictedClassPassable"
print("trying validateClosureName(functionName)")
try validateClosureName(functionName)//this is in case you refactor/change the function name and the "constant" above is no longer valid
print("trying RestrictedAccessClass.run")
try RestrictedAccessClass.run(functionName, in: self, with: ["paramkey":"paramvalue"])
let returningFunctionName = "anotherRestrictedClassPassable"
print("trying validateClosureName(returningFunctionName)")
try validateClosureName(returningFunctionName)
print("trying RestrictedAccessClass.runAndReturn")
let result = (try RestrictedAccessClass.runAndReturn(returningFunctionName, in: self, with: ["paramkey":"ParamValueChanged"]) as! String?) ?? "NIL, something went wrong"
print("result is \(result)")
}
func validateClosureName(_ name:String) throws {
let mirror = Mirror(reflecting: self)
var functionNameIsPresent = false
for child in mirror.children {
if child.label != nil && child.label! == name {
functionNameIsPresent = true
break
}
}
guard functionNameIsPresent else {
print("invalid function")
throw AccessError.InvalidFunction
}
}
}
extension Mirror {
func getChildrenDict() -> [String:Any]
{
var dict = [String:Any]()
for child in children
{
if let name = child.label
{
dict[name] = child.value
}
}
return dict
}
}
class RestrictedAccessClass:AccessRestricted {
private static var shared:[String:Any] = [
"restrictedVariable" : "You can't access me!"
]
private static func validateType<T>(of classObject:T) throws {
switch classObject {
case is Accessor:
return
default:
print("Invalid access class")
throw AccessError.InvalidAccessClass
}
}
var restrictedVariable:String
private init() {
restrictedVariable = "You can't access me!"
}
private init(from json:[String:Any]) {
restrictedVariable = json["restrictedVariable"] as! String
}
static func run<T:AnyObject>(_ closureName:String, in classObject: T, with parameters:Any?) throws {
print("trying validateType(of: classObject) in run")
try validateType(of: classObject)
for child in Mirror(reflecting: classObject).children {
if let childName = child.label {
if childName == closureName {
let dropClosure = child.value as! DropClosureVoid<RestrictedAccessClass>
let selfInstance = RestrictedAccessClass(from:shared)
let interface = WeaklyConnectedInterface(selfInstance)
dropClosure(interface, parameters)
runCleanup(on: selfInstance)//parses any data changed by the end of the drop closure back into the dict for use in future instances. This means you mustn't try using the instance in an async closure. The correct way to do this would be to call run inside of an async closure, rather than putting an anync closure inside of the drop closure.
_ = interface.value
return
}
}
}
}
static func runAndReturn<T:AnyObject>(_ closureName:String, in classObject: T, with parameters:Any?) throws -> Any? {
print("trying validateType(of: classObject) in runAndReturn")
try validateType(of: classObject)
for child in Mirror(reflecting: classObject).children {
if let childName = child.label {
if childName == closureName {
let dropClosure = child.value as! DropClosureAny<RestrictedAccessClass>
let selfInstance = RestrictedAccessClass(from:shared)
let interface = WeaklyConnectedInterface(selfInstance)
let result = dropClosure(interface, parameters)
runCleanup(on: selfInstance)//parses any data changed by the end of the drop closure back into the dict for use in future instances. This means you mustn't try using the instance in an async closure. The correct way to do this would be to call run inside of an async closure, rather than putting an anync closure inside of the drop closure.
_ = interface.value
return result
}
}
}
return nil
}
private static func runCleanup(on instance:RestrictedAccessClass) {
shared = Mirror(reflecting:instance).getChildrenDict()
//once this function goes out of scope(or shortly thereafter), the instance passed will become useless as a shared resource
}
}
Code to encounter error:
I just put this in a new project's AppDelegate.application(didFinishLaunching). You can put all of the code above and below, in order, in a playground and it will break in the same spot, but not as clearly.
let accessor = Accessor()
do {
try accessor.runRestrictedClassPassable()
}
catch {
print(error.localizedDescription)
}
Updates
Whether zombie objects are turned on or off, I'm getting the same error message from Xcode: Thread 1: EXC_BAD_ACCESS (code=1, address=0x1a1ebac696e)
Running an analysis with Command+Shift+B reveals no warnings.
Running with all of the malloc options enabled reveals the following error:
Thread 1: signal SIGABRT, objc[somenumber]: Attempt to use unknown class 0xSomevalue
This just got weird...
Apparently, the "unknown class" is the project. I found this out by selecting the (i) bubble on the inline object inspector for the Restricted instance that was causing the crash. It gives me the following message:
Printing description of weaklyConnectedInterface:
expression produced error: error:
/var/folders/zq/_x931v493_vbyhrfc25z1yd80000gn/T/expr52-223aa0..swift:1:65:
error: use of undeclared type 'TestProject'
Swift._DebuggerSupport.stringForPrintObject(Swift.UnsafePointer<TestProject.RestrictedAccessClass>(bitPattern: 0x103450690)!.pointee)
^~~~~~~~~~~
I thought that maybe this would happen for other classes, so I tested, and it's able to access other project-level classes just fine. Only for this specific instance is the project "namespace" undefined.
Please find below required modifications (not many)... Tested with Xcode 11.2 / iOS 13.2.
1) made interface inout to pass it as-is original, otherwise it somehow copied loosing type information
typealias DropClosureVoid<T: AnyObject & AccessRestricted> =
(_ weaklyConnectedInterface: inout WeaklyConnectedInterface<T>, _ usingParameters: Any?)->Void
typealias DropClosureAny<T: AnyObject & AccessRestricted> =
(_ weaklyConnectedInterface: inout WeaklyConnectedInterface<T>, _ usingParameters: Any?)->Any?
2) fix places of usage (same in two places)
var interface = WeaklyConnectedInterface(selfInstance) // made var
dropClosure(&interface, parameters) // << copy closure args here was a reason of crash
3) ... and that's it - build & run & output
Note: I would recommend to avoid force unwrap and use the following
if let dropClosure = child.value as? DropClosureVoid<RestrictedAccessClass> {
dropClosure(&interface, parameters)
}
I'm using generics to dynamically assign the type of the value that the response should be, at the call site of the function.
The function below is the only accessible method my FirebaseClient class has.
It is called in many different places.
To make sure the correct object is in the response, I insert what object I'm expecting at the call site of the function. Here is the catch. If I'm posting a value to database, I dont expect any response, and only care about error, but am forced to put an arbitrary type for param/argument, even though i know it will be nil for such cases.
How can I set a default value for generic parameter, so that no one could hypothetically come along and insert an object as response when they won't get one?
Hopefully the code speaks for itself and makes more sense than I did.
Other info:
Inside the method below, if its a GET request, I initialize T with the json response. As you see the generic has to conform to QueryType protocol, which just contains an initializer, so each object that is T, has an initializer to handle response in its own way.
func fireRequest<T: QueryType>(_ request: FirebaseRequest, completion: #escaping (_ data: [T]? = [], _ error: FirebaseError?) -> Void ) {
// setting default value to data param throws error.
}
Successful use case:
client.fireRequest(FirebaseRequest.observe(path: path), completion: { (data: [User], error: FirebaseError? ) in
// Since I infer 'T' to be of type User, i can expect a collection of users, or single user as my response. This is what I want.
})
Error Use case:
client.fireRequest(FirebaseRequest.setValue(path: path, value: locationData), completion: { (_, error: FirebaseError? ) in
// error: generic parameter 'T' could not be inferred.
// In this case, I am posting some data to database, so I dont expect a response, but putting underscore throws error.
})
I am not exactly sure what you are asking but you can use T() to generate the defualt value for the type.
As for the underscore it is because (_, FirebaseError?)->Void is not the same type as ([T], FirebaseError?)->Void. So your closure should be
{(_:[AnyObject]?, error: FirebaseError?) in code }
If you want this to use generics you would need to define some function like
func errorCaseCompletetion<T>( _ : [T]?, error: FirebaseError?){
//code
}
And then you just pass the function name as the completetion block.
I'm using Realm in my app. I'm trying a implement a unified error handling interface for all types of errors. For example, I have a class that handles all User related tasks. So I have an enum called UserError.
import Foundation
import RealmSwift
enum UserError: Error {
case doesNotExist
case alreadyExists
case databaseError(error: Error)
}
class UserHelper {
/// Fetch user object for the given email if exists.
func getUser(forEmail email: String) throws -> User {
do {
guard let user = try Realm().object(ofType: User.self, forPrimaryKey: email) else {
throw UserError.doesNotExist
}
return user
} catch {
throw UserError.databaseError(error: error)
}
}
}
I have a separate catch-all databaseError enum value to catch all Realm related errors.
The problem with my method is, when I throw the doesNotExist error inside the do-catch where I query the database, that error gets caught inside this method's catch and gets re-thrown as a databaseError. I want the error to arrive as the original type, doesNotExist.
How do I accomplish this?
Your catch clause is unqualified and therefore catches every error thrown within the do clause, whether or not it's a Realm error or a UserError. You can try making the catch clause conditional, since you only want to throw a databaseError() if the error is indeed a Realm error:
do {
guard let user = try Realm().object(ofType: User.self, forPrimaryKey: email) else {
throw UserError.doesNotExist
}
return user
} catch let error as Realm.Error {
throw UserError.databaseError(error: error)
}
If you do this, you can also change your UserError.databaseError case to take a Realm.Error instead of a plain Error, giving whatever code catches your error more information about the specific database error.
Using Swift 2.1 (Xcode 7.2.) and Parse 1.12.0, I'm getting an error that PFObject.save() is unavailable in Swift. My code is:
let operation = NSBlockOperation { () -> Void in
do {
let success = try rating.save()
}
catch let er as NSError {
error = er
}
}
In PFObject+Synchronous.h, there is this:
///--------------------------------------
#pragma mark - Saving Objects
///--------------------------------------
/**
*Synchronously* saves the `PFObject`.
#return Returns whether the save succeeded.
*/
- (BOOL)save PF_SWIFT_UNAVAILABLE;
/**
*Synchronously* saves the `PFObject` and sets an error if it occurs.
#param error Pointer to an `NSError` that will be set if necessary.
#return Returns whether the save succeeded.
*/
- (BOOL)save:(NSError **)error;
So it seems as if Xcode can't tell which function to use: it should try to use the one that handles the error. Is there a way of forcing this, or am I calling the function incorrectly?
Although the function not marked as unavailable to swift:
-(BOOL)save:(NSError **)error
is defined to return a bool, the Swift implementation (which throws) apparently does not, so the code compiles fine if I'm not expecting to receive a return value, i.e.:
let operation = NSBlockOperation { () -> Void in
do {
try rating.save()
}
catch let er as NSError {
error = er
}
}
I'm still now sure how I could have determined this without trial and error.
The first overload is marked unavailable to Swift, hence it is not visible.
The second overload is made available, but as you discovered yourself, it requires a try since it returns a NSError output parameter. The BOOL return value in Cocoa is there to indicate whether the operation was successful or not. In Swift, this is handled by catching the NSError instead. This behaviour was introduced in (I think) Swift 2.0, and is documented here.
To summarize, an Obj-C method
- (BOOL) doSomething:(NSError**)error {}
maps to the following Swift method
func doSomething() throws