get error in swift side form objective-c side - objective-c

I try to get error object from this function of ZipArchive
guard ZipArchive.unzipFileAtPath(filePath as String,toDestination: folderPath as String,overwrite: true, password: nil,error: whatShouldGoHere) else
{
throw whatShouldGoHere
}
My question is how to get back whatShouldGoHere form this unzipFileAtPath Objective-C function ?
I note that in the define of unzipFileAtPath function have access NSError object to whatShouldGoHere parameter
NSError *err = [NSError errorWithDomain:#"ZipArchiveErrorDomain" code:-1 userInfo:userInformation];
if (error) {
error = err;
}

I will use this library ZipArchive to show you how to get the error object from calling objective-c functions.
In this library, it also has the same above function.
+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError **)error;
In swift 2.1, you can use Handling Errors Using Do-Catch to get the error object.
do {
try SSZipArchive.unzipFileAtPath(filePath, toDestination: folderPath, overwrite: true, password: nil)
} catch {
print(error)
}

If you want to write a function to rethrow the error received from ZipArchive don't guard the boolean result but catch the error in a do - catch block and throw it.
do {
try SSZipArchive.unzipFileAtPath(filePath as String,
toDestination: folderPath as String,
overwrite: true,
password: nil)
} catch let error as NSError {
throw error
}

Related

Converting objective-c block to Swift closure

I am trying to convert this Objective-C block into Swift:
[self.client downloadEntity:#"Students" withParams: nil success:^(id response) {
// execute code
}
failure:^(NSError *error) {
// Execute code
}];
This is my code in Swift, but the syntax seems to be a bit off:
client.downloadEntity("Students", withParams: nil, success: {(students: [AnyObject]!) -> Void in
print("here")
}, failure: { (error: NSError!) -> Void! in
print ("here")
}
This is giving me a few compilation errors:
Value of 'AnyObject' has no member 'downloadEntity'
It is complaining about the lack of commas (,) right after the failure part of the code
Try this:
client.downloadEntity("Student", withParams: nil,
success: { (responseObj) -> Void in
print("success: \(responseObj)")
},
failure: { (errorObj) -> Void in
print("treat here (in this block) the error! error:\(errorObj)")
})
You need to switch to the new Swift error syntax, and you can also using trailing closures. I had to use a bool for the example to show how you would call your success closure, or you would throw an error.
var wasSuccessful = true // This is just here so this compiles and runs
// This is a custom error type. If you are using something that throws an
// NSError, you don't need this.
enum Error:ErrorType {
case DownloadFailed
}
// Hopefully you have control over this method and you can update
// the signature and body to something similar to this:
func downloadEntity(entityName: String, success: ([AnyObject]) -> Void) throws {
let students = [AnyObject]()
// download your entity
if wasSuccessful {
// Call your success completion handler
success(students)
}
else {
throw Error.DownloadFailed
}
}
When you have a function that can throw an error, you need to call it with try inside a do/catch block.
// Calling a function that can throw
do {
try downloadEntity("Students") { students in
print("Download Succeded")
}
}
catch Error.DownloadFailed {
print("Download Failed")
}
// If you are handling NSError use this block instead of the one above
// catch let error as NSError {
// print(error.description)
// }

ObjC error throwing function returning () instead of BOOL

I have an Objective C function declared as:
+ (BOOL)isScanningUnsupported:(NSError **)error;
and if it returns true, I have to return nil in the function i am calling it from (Swift).
So I call if like this:
var isUnsupported = false
do { try isUnsupported = PPCoordinator.isScanningUnsupported()
} catch let error { throw error }
if isUnsupported {return nil }
But it tells me:
Cannot assign a value of type '()' to a value of type 'Bool'
In Objective C it was called like:
if ([PPCoordinator isScanningUnsupported:error]) {
return nil;
}
what can I do????
You are describing the standard way that functions that produce an error in Objective-C are interpreted in Swift. Methods in Objective-C that take a pointer to an error and return BOOL are assumed to be void and throw in Swift by default.
This is because that is almost always what it means in Objective-C. i.e. true means "ran successfully", false means "failed and I put the error in the pointer you supplied".
Your method doesn't conform to normal Objective-C conventions so you could try disabling Swift's conversion to a throwing function with the NS_SWIFT_NOTHROW macro on the declaration of PPCoordinator.isScanningUnsupported.
I think you want:
var isUnsupported = false
do { try PPCoordinator.isScanningUnsupported()
isUnsupported = true
} catch let error {
throw error // or do nothing?
}
if isUnsupported {return nil }
If you look at the Swift definition of your function, I would expect no return value (i.e. void).
this is working now for me:
if let _ = try? PPCoordinator.isScanningUnsupported() { return nil }

Throwing on unwrapping nil optional

Consider the following code:
enum MyErrorType:ErrorType {
case BadTimes
}
var mightHaveAValue: String?
do {
if let value = mightHaveAValue {
// do stuff with value
} else {
throw MyErrorType.BadTimes
}
// do stuff with NSFileManager using mightHaveAValue which might throw
} catch {
// handle error
}
...in which I have a large do/try/catch block. In this instance the error handling will be the same, whether mightHaveAValue is empty or something bad happens with NSFileManager later on. So it makes sense to re-use the error handling code.
Is this the cleanest approach going in Swift2, or is there some way I can automatically throw/catch on unwrapping an optional with no value?
It looks ok, but it's even better with guard let instead of if let because it lets you use the unwrapped value in the main do block instead of having to work inside an if let branch. You can also use several catch branches to handle different error types.
do {
guard let value = mightHaveAValue else {
throw MyErrorType.BadTimes
}
// do stuff with value
} catch let error as MyErrorType {
// handle custom error
} catch let error as NSError {
// handle generic NSError
}
There is no automatic way to handle unwrapping optionals, you have to use one of the many known ways: if let, guard let, nil coalescing, etc.
Maybe just use an extension like this 🤔
extension Optional {
func throwing() throws -> Wrapped {
if let wrapped = self {
return wrapped
} else {
throw NSError("Trying to access non existing value")
}
}
}

Return Value from Function Swift

I know this is probably a simple queston, I would like to return the value of currentLocGeoPoint and return the array of Objects which is of type PFObject.
Tried to save it as a global variable, but it doesn't work because it is asynchronous and doesn't take a value yet. Returns empty.
Tried to return currentLocGeoPoint and changed Void in to PFGeoPoint in. Gives error: PFGeoPoint is not convertible to 'Void'
So I'm not sure how I can fetch the variable currentLocGeoPoint.
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler: { (placemarks, error) -> Void in
if (error != nil) {
println("Error:" + error.localizedDescription)
//return
}
if placemarks.count > 0 {
let pm = placemarks[0] as CLPlacemark
self.displayLocationInfo(pm)
currentLoc = manager.location
currentLocGeoPoint = PFGeoPoint(location:currentLoc)
var query = PFQuery(className:"Bar")
query.whereKey("BarLocation", nearGeoPoint:currentLocGeoPoint, withinMiles:10)
query.limit = 500
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]!, error: NSError!) -> Void in
if objects != nil {
} else {
println("error: \(error)")
}
}
} else {
println("error: \(error)")
}
})
}
I don't understand the notion of "I want to return currentLocGeoPoint". Return it to what? You're in a CLLocationManagerDelegate method, so there's no one to return it to.
What you could do, though, is, when the request is done (i.e. within this closure), call some other function that needed the currentLocGeoPoint. Or you could update the UI to reflect the updated information (make sure to dispatch that update to the main thread, though). Or, if you have other view controllers or model objects that need to know about the new data, you might post a notification, letting them know that there is an updated currentLocGeoPoint. But within this method, there's no one to whom you would "return" the data.
You could assign it to a stored property of your class. Just use
self.<property> = currentLocGeoPoint

Objc to swift bridge `use of undeclared identifier 'cocoarr'`

I'm combining Swift and Objective-C in the same project. I am trying to use STTwitter cocoapod like this:
// objective-c
// STTwitter category method
//
- (void)getStatusesLookupTweetIDs:(NSArray *)tweetIDs
successBlock:(void (^)(NSArray *))successBlock
errorBlock:(void (^)(NSError *))errorBlock {
[self getStatusesLookupTweetIDs:tweetIDs
includeEntities:#(YES)
trimUser:#(YES)
map:#(YES)
successBlock:successBlock
errorBlock:errorBlock];
}
Swift Code
// swift
twitterApi.getStatusesLookupTweetIDs(ids, successBlock: { (tweets: [AnyObject]!) -> Void in
process(tweets)
finish()
}, errorBlock: { (err) -> Void in
error(err)
})
Everything looks fine in Obj-C (I tried not investigate variable passed to successBlock, they all have valid values). But in Swift, when successBlock gets executed, tweets was:
Printing description of tweets:
([AnyObject]!) tweets = 1 value {
[0] = <error: use of undeclared identifier 'cocoarr'
error: 1 errors parsing expression
>
}
How do I fix this and pass NSArray into Swift? (No compile error)
That worked for me.
Instead of using:
[AnyObject]
try to use:
[Dictionary<String, AnyObject>] (or whatever class is inside the array)
Try to specify the type of the array instead AnyObject.
I hope it helps.
Cheers.
Try [[String:AnyObject]] rather than [AnyObject]
I got the same error in a smilar functionality. When changing from:
if let dictOrList = NSJSONSerialization.JSONObjectWithData(data, options:nil, error: &err) as? NSDictionary {
callbackList = [dictOrList]
} else if let list = NSJSONSerialization.JSONObjectWithData(data, options:nil, error: &err) as? [AnyObject] {
callbackList = list
}
to
if let dictOrList = NSJSONSerialization.JSONObjectWithData(data, options:nil, error: &err) as? [String: AnyObject] {
callbackList = [dictOrList]
} else if let list = NSJSONSerialization.JSONObjectWithData(data, options:nil, error: &err) as? [[String:AnyObject]] {
callbackList = list
}
I got it working.