Should we do nil check for non-optional variables? - swift

I have a function (abc) as follows and I should throw an error when the arguments passed are empty or nil, should I check for nil too or only empty is enough?
public func abc(forURL serviceUrl:String,serviceID:String, error:inout Error? )throws ->[AnyHashable : Any]{
guard serviceUrl != nil, !serviceUrl.isEmpty else {
let argError:Error = MapError.emptyArgumentUrl.error()
error = argError
throw argError
}
guard !serviceID.isEmpty else {
let argError:Error = MapError.emptyArgumentServiceId.error()
error = argError
throw argError
}

serviceID is not an optional.
That means it can't be nil.
So no, there is no need for that check.

Related

Upgraded from Kanna 2.2.1 to 4.0.2 and getting the same error

I am rewriting a project I found on Github to learn and teach myself how to use swift and pod files. I upgraded Kanna from 2.2.1 to 4.0.2 because I was getting an arm64 error.
With 4.0.2 I am getting the error:
Initializer for conditional binding must have Optional type, not 'HTMLDocument'
Call can throw, but it is not marked with 'try' and the error is not handled
I am unsure about what this error means and how to fix it. It is associated with this if statement:
if let doc = Kanna.HTML(html: htmlText, encoding: String.Encoding.utf8) {
for itemSize in doc.css("option[value^='']") {
let itemSizeText = itemSize.text!.lowercased()
let wishListItemSize = self.websiteInstance!.websiteWishListItem.size!.lowercased()
if itemSizeText.range(of: wishListItemSize) != nil {
print("Found size")
foundItemSize = true
let itemSizeValue = itemSize["value"]
self.websiteInstance!.viewController!.websiteBrowser!.evaluateJavaScript("document.getElementById(\"size-options\").value = \(itemSizeValue!)", completionHandler: nil)
break
}
countSize += 1
}
}
The type signature for the method you are calling is public func HTML(html: String, url: String? = nil, encoding: String.Encoding, option: ParseOption = kDefaultHtmlParseOption) throws -> HTMLDocument. The function returns a non-Optional value, but can throw an error.
You can handle the error by either using the try? keyword to make the function return nil in case an error was thrown and make the optional binding you currently use work like this:
if let doc = try? Kanna.HTML(html: htmlText, encoding: String.Encoding.utf8) {...
or rather use try and put the function call in a do-catch block to see the actual error in case any was thrown.
do {
let doc = Kanna.HTML(html: htmlText, encoding: String.Encoding.utf8)
for itemSize in doc.css("option[value^='']") {
let itemSizeText = itemSize.text!.lowercased()
let wishListItemSize = self.websiteInstance!.websiteWishListItem.size!.lowercased()
if itemSizeText.range(of: wishListItemSize) != nil {
print("Found size")
foundItemSize = true
let itemSizeValue = itemSize["value"]
self.websiteInstance!.viewController!.websiteBrowser!.evaluateJavaScript("document.getElementById(\"size-options\").value = \(itemSizeValue!)", completionHandler: nil)
break
}
countSize += 1
}
} catch {
print(error)
// Handle error
}

Trying to do deal with errors and optionals the right way

I am attempting to use SwiftSoup to scrape some HTML. This example, based on the SwiftSoup github documentation, works fine…
func scrape() throws {
do {
let htmlFromSomeSource = "<html><body><p class="nerp">HerpDerp</p><p class="narf">HoopDoop</p>"
let doc = try! SwiftSoup.parse(htmlFromSomeSource)
let tag = try! doc.select("p").first()!
let tagClass = try! tag.attr("class")
} catch {
print("oh dang")
throw Abort(.notFound)
}
print(tagClass)
}
… Up until I mess with the selector or attribute targets, at which point everything crashes thanks to the implicitly unwrapped optionals (which I assume was just quick-and-dirty code to get smarter people started). That do/catch doesn't seem to help at all.
So what's the Right way? This compiles...
print("is there a doc?")
guard let doc = try? SwiftSoup.parse(response.body.description) else {
print("no doc")
throw Abort(.notFound)
}
print("should halt because there's no img")
guard let tag = try? doc.select("img").first()! else {
print("no paragraph tag")
throw Abort(.notFound)
}
print("should halt because there's no src")
guard let tagClass = try? tag.attr("src") else {
print("no src")
throw Abort(.notFound)
}
... but again if I mess with the selector or attribute it crashes out, "Unexpectedly found nil while unwrapping an Optional value" (after "is there a doc?"). I thought guard would halt the process when it encountered a nil? (If I convert "try?" to "try" the compiler complains that "initializer for conditional binding must have Optional type"…)
If you declare the function as throws you don't need a do - catch block inside the function. Just remove the block and the exclamation marks after try to pass through the errors to the caller function.
func scrape() throws { // add a return type
let htmlFromSomeSource = "<html><body><p class="nerp">HerpDerp</p><p class="narf">HoopDoop</p>"
let doc = try SwiftSoup.parse(htmlFromSomeSource)
guard let tag = try doc.select("p").first() else { throw Abort(.notFound) }
let tagClass = try tag.attr("class")
// return something
}

Swift: Determining if cast to integer from string succeeds

Below is my code
func contactForUpdates() -> Int {
//contact server for most recent version
let versionURL = settings.versionURL
if let url = URL(string: versionURL) {
do {
let contents = try NSString(contentsOf: url, usedEncoding: nil)
//NEXT LINE IS WHERE THE QUESTIONS LIES
return Int(contents as String)!
} catch {
// contents could not be loaded
processError("Current version could not be loaded.")
return Int(0)
}
} else {
// the URL was bad!
processError("Current version could not be loaded--URL was bad.")
return Int(0)
}
}
If the URL loads, it will return a single integer. A bad internet connection, such as an airport that requires a login prior to internet access, will not return an integer, but a full HTML page that requests a login. forcing a downcast with return Int(contents as String)! will produce the error fatal error: unexpectedly found nil while unwrapping an Optional value.
I assumed that this would run the catch statement when I wrote this, but instead it returns a fatal error. How can I catch this?
If 0 represents an error for you, you could do:
return Int(contents as String) ?? 0
?? is called the "nil coalescing operator". It returns the first value if it's not nil, otherwise it returns the second value.
If you want more robust handling you could use guard…
guard let value = Int(contents as String) else {
processError("Something went horribly wrong")
return 0
}
return value
That's because you are forcing an optional value to be non optional.
You have to check if the conversion is possible:
if let number = Int(contents as String) {
return number
}
return -1 // Or something you will recognise as error
func contactForUpdates() -> Int {
//contact server for most recent version
let versionURL = settings.versionURL
if let url = URL(string: versionURL) {
do {
let contents = try NSString(contentsOf: url, usedEncoding: nil)
if let vers = Int(contents as String) {
return vers
}
else {
processError("Current version could not be loaded--Possibly proxy interception")
return Int(0)
}
//return Int(contents as String)!
} catch {
// contents could not be loaded
processError("Current version could not be loaded.")
return Int(0)
}
} else {
// the URL was bad!
processError("Current version could not be loaded--URL was bad.")
return Int(0)
}
}
Fixes the error, although makes the do/catch run the catch statement. I am not sure why? I hope that somebody can answer that, but otherwise this statement fixes it.

SwiftCoreDataHelper.swift error in xcode 7

Could help me guys with the following three errors in SwiftCoreDataHelper.swift. I am using xcode 7 but its seems that the code for older versions of xcode. thanks in advance.
1 . . .
line error: let items: NSArray = managedObjectContext.executeFetchRequest(<#T##request: NSFetchRequest##NSFetchRequest#>)
error: Call can throw, but it is not marked with 'try' and the error
is not handled
class func fetchEntities(className:NSString, withPredicate predicate:NSPredicate?, managedObjectContext:NSManagedObjectContext)->NSArray{
let fetchRequest:NSFetchRequest = NSFetchRequest()
let entetyDescription:NSEntityDescription = NSEntityDescription.entityForName(className as String, inManagedObjectContext: managedObjectContext)!
fetchRequest.entity = entetyDescription
if predicate != nil {
fetchRequest.predicate = predicate!
}
fetchRequest.returnsObjectsAsFaults = false
let items: NSArray = managedObjectContext.executeFetchRequest(<#T##request: NSFetchRequest##NSFetchRequest#>)
return items
}
2 . . .
line error: if managedObjectContext.save(nil) {
error: Nil is not compatible with expected argument type '()'
class func saveManagedObjectContext(managedObjectContext:NSManagedObjectContext)->Bool{
if managedObjectContext.save(nil) {
return true
}
else {
return false
}
}
3 . . .
line error: if storeCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil, error:&error ) != nil {
error: Contextual type '[NSObject : AnyObject]' cannot be used with
array literal
if storeCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil, error:&error ) != nil {
if error != nil {
print(error!.localizedDescription)
abort()
}
}
Read about do try throw and catch. If a call throws you should enclose it in a do block and handle the error with catch.
Remove the nil. No argument is expected. You may then have to handle thrown errors.
Not quite sure what the error is here but again this needs converting to Swift 2 error handling and should probably look something like this. Note the error argument has become a thrown error. This is untested no promises that it is absolutely correct.
do {
let coordinator = try storeCoordinator.addPersistentStoreWithType(
NSSQLiteStoreType,
configuration: nil,
URL: url, options: nil)
} catch {
print(error)
abort()
}

Optional enum initializer not working with where clause

I'm having trouble composing a guard with a where clause and want to verify whether I'm doing this correctly or if the compiler is being buggy.
I have this enum:
enum Command: String {
case Init
case Update
}
And then this guard statement
let cmdStr = "Init"
guard let command = Command(rawValue: cmdStr) where command != nil else {
print("invalid command: \(cmdStr)") // Error: Value of type Command can never be nil, comparison isn't allowed
return nil
}
The error I get is strange, because the rawValue initializer is an optional initializer. Introspecting command shows that it is type Command though, even though the initializer results in an optional.
However, if I do this outside the guard statement first and rewrite like this:
let cmdStr = "Init"
let cmd = Command(rawValue: cmdStr)
guard cmd != nil else {
print("invalid command: \(cmdStr)")
return nil
}
It works and introspection of cmd shows the expected type of Command?
Does anyone know why this is happening? Or is this a compiler bug I should be submitting?
Please, read Apple Documentation about guard statement:
https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-ID525
In your case there should be
let cmdStr = "Init"
guard let command = Command(rawValue: cmdStr) else {
print("invalid command: \(cmdStr)") // Error: Value of type Command can never be nil, comparison isn't allowed
return nil
}