I have a swift function func hexStrToBytes(input: String) throws -> [UInt8] to translate HEX string into Uint8 array, which may need to throw exceptions when the format of input is not correct.
But I can't verify its format by myself, instead I use bytes.append(UInt8(str,radix: 16)!). If this function executes successfully, then my function can return a correct value. If something wrong with this bytes.append(UInt8(str,radix: 16)!), I need to throw a exception. But how do I know it's wrong? This program may just crush and I even don't have chance to throw exceptions.
This snippet should be close to what you're looking for. It uses optional binding to check if the string is convertible and throws an error if is not.
if let theByte = UInt8(str, radix: 16) {
bytes.append(theByte)
} else {
throw MyError()
}
Note that Swift doesn't use the term "exceptions" to describe its error-handling mechanisms. While the throw/catch control flow is similar, they are not implemented the same way as exceptions in other languages.
Related
when looking for Information when and why to use Exceptions there are many people (also on this platform) making the point of not using exceptions when validating user-input because invalid input is not an exceptional thing to happen.
I now have the case where I have to parse a complex string of user input and map it to an Object-Tree basically, similar to a Parser.
Example in pseudo code:
input:
----
hello[5]
+
foo["ok"]
----
results in something like that:
class Hello {
int id = 5
}
class Add {}
class foo {
string name = 'ok'
}
Now in order to "validate" that input I have to parse it, having code that parses the input for validation and code to create the objects separately feels redundant.
Currently I'm using Exceptions while parsing single tokens to collect all Errors.
// one token is basically a single
try {
foreach (token in tokens) {
factory = getFactory(token) // throws ParseException
addObject(factory.create(token)) // throws ParseException
}
} catch (ParseException e) {
// e.g. "Foo Token expects value to be string"
addError(e)
}
is this bad use of exceptions?
An alternative would be to inject a validation class in every factory or mess around with return types (feels a bit dirty)
If exceptions work for your use case, go for it.
The usual problem with exceptions is that they don't let you fix things up and continue, which makes it hard to implement parser error recovery. You can't really fix up a bad input, and you probably shouldn't even in cases where you could, but error recovery lets you report more than one error from the same input, which is often considered convenient.
All of that depends on your needs and parsing strategy, so there's not a lot of information to go on here.
I'm using the GRDB library to integrate SQLite with my iOS application project. I declared a DatabaseQueue object in AppDelegate.swift like so:
var DB : DatabaseQueue!
In the same file, I had provided a function for connecting the above object to a SQLite database which is called when the app starts running. I had been able to use this in one of my controllers without problems (as in, the app doesn't have problems running using the database I connected to it), like so:
var building : Building?
do {
try DB.write { db in
let building = Building.fetchOne(db, "SELECT * FROM Building WHERE number = ?", arguments: [bldgNumber])
}
} catch {
print(error)
}
However, in another controller, the same construct is met with an error,
Value of optional type 'DatabaseQueue?' must be unwrapped to refer to member 'write' of wrapped base type 'DatabaseQueue'
with the only difference (aside from the code, of course) being that there are return statements inside the do-catch block, as the latter is inside a function (tableView for numberOfRowsInSection) that is supposed to return an integer. The erroneous section of code is shown below.
var locsCountInFloor : Int
do {
try DB.write { db in
if currentBuilding!.hasLGF == true {
locsCountInFloor = IndoorLocation.filter(bldg == currentBuilding! && level == floor).fetchCount(db)
} else {
locsCountInFloor = IndoorLocation.filter(bldg == currentBuilding! && level == floor + 1).fetchCount(db)
}
return locsCountInFloor
}
} catch {
return 0
}
Any help would be greatly appreciated!
As is often the case when you have a problem with a generic type in Swift, the error message is not helpful.
Here’s the real problem:
DB.write is generic in its argument and return type. It has a type parameter T. The closure argument’s return type is T, and the write method itself returns T.
The closure you’re passing is more than a single expression. It is a multi-statement closure. Swift does not deduce the type of a multi-statement closure from the statements in the closure. This is just a limitation of the compiler, for practical reasons.
Your program doesn’t specify the type T explicitly or otherwise provide constraints that would let Swift deduce the concrete type.
These characteristics of your program mean Swift doesn’t know concrete type to use for T. So the compiler’s type checker/deducer fails. You would expect to get an error message about this problem. (Possibly an inscrutable message, but presumably at least relevant).
But that’s not what you get, because you declared DB as DatabaseQueue!.
Since DB is an implicitly-unwrapped optional, the type checker handles it specially by (as you might guess) automatically unwrapping it if doing so makes the statement type-check when the statement would otherwise not type-check. In all other ways, the type of DB is just plain DatabaseQueue?, a regular Optional.
In this case, the statement won’t type-check even with automatic unwrapping, because of the error I described above: Swift can’t deduce the concrete type to substitute for T. Since the statement doesn’t type-check either way, Swift doesn’t insert the unwrapping for you. Then it carries on as if DB were declared DatabaseQueue?.
Since DatabaseQueue? doesn’t have a write method (because Optional doesn’t have a write method), the call DB.write is erroneous. So Swift wants to print an error message. But it “helpfully” sees that the wrapped type, DatabaseQueue, does have a write method. And by this point it has completely forgotten that DB was declared implicitly-unwrapped. So it tells you to unwrap DB to get to the write method, even though it would have done that automatically if it hadn’t encountered another error in this statement.
So anyway, you need to tell Swift what type to use for T. I suspect you meant to say this:
var locsCountInFloor: Int
do {
locsCountInFloor = try DB.write { db in
...
Assigning the result of the DB.write call to the outer locsCountInFloor is sufficient to fix the error, because you already explicitly defined the type of locsCountInFloor. From that, Swift can deduce the return type of this call to DB.write, and from that the type of the closure.
In JavaScript we have something like .toString which can convert the entire function object to string.
Do we have something similar on IOS?
For example, in JavaScript if we have function like this, after converting it with .toString and printing the value in console we see the entire function object.
function sum(a, b)
{
return a + b;
}
console.log(sum.toString());
// expected output:
// "function sum(a, b)
// {
//return a + b;
// }"
Can we do something similar for IOS? I tried String (describing :Function) in Swift but that didn't work and gave me output as (Function) but not the complete structure like we get in JavaScript .toString.
public func say_hello()
{
print("Hello, World!")
}
String(describing: say_hello))
//Output:(Function)
Despite the many comments explaining why that's not possible (nor feasible in many cases), I want to point out that you can use JavaScript code in your Swift app and thus use the serialization mechanism of that language. Have a look at JSContext for details. This of course won't make things simpler, but it does give extra flexibility with injecting/changing/extending functionality at runtime.
This is not possible from Swift/Objc
According to Apple Swift documentation defer
This statement lets you do any necessary cleanup that should be performed regardless of how execution leaves the current block of code whether it leaves because an error was thrown or because of a statement such as return or break.
documentation
But this code:
enum SomeError: ErrorType {
case BadLuck
}
func unluckey() throws {
print("\n\tunluckey(💥) -> someone will have a bad day ;)\n")
throw SomeError.BadLuck
}
func callsUnluckey() throws {
print("callsUnluckey() -> OPENING something")
defer {
print("callsUnluckey(😎) -> CLOSEING something")
}
print("callsUnluckey() -> WORKING with something")
try unluckey()
print("callsUnluckey() -> will never get here so chill...")
defer {
print("callsUnluckey(💩) -> why this is not getting called?")
}
}
do {
try callsUnluckey()
} catch {
print("")
print("someone had a bad day")
}
Produces this result in the console:
callsUnluckey() -> OPENING something
callsUnluckey() -> WORKING with something
unluckey(💥) -> someone will have a bad day ;)
callsUnluckey(😎) -> CLOSEING something
someone had a bad day
And my question is: why the last defer in callsUnluckey() is not getting called?.
Take a look at the language grammar, as summarized in The Swift Programming Language:defer is a statement. In the grammar, a statement is imperative code to be run in order (as opposed to the definition of a program element, like a class or function, to be later used in imperative code).
Note also the bit right after the part you quoted, on order dependence. If defer was just a declaration, like a function or property or type declaration, there couldn't be an ordering effect. (It doesn't matter what order you put function declarations in, for example.)
IIRC (on mobile right now, can't check easily), the compiler will catch you if you put a defer after a return, noting that it is code that will never be executed.
Remember that "throwing" in Swift is, under the hood, really just a special kind of return type. So if your function throws, no code after the throw will be executed (and thus no defer statement will be able to set up a code block to be later executed). When you declare a function throws, any call in it to another throwing function effectively becomes a possible throw statement, which itself is effectively a return.
I am trying to implement some code from parse.com and I notice a keyword in after the void.
I am stumped what is this ? The second line you see the Void in
PFUser.logInWithUsernameInBackground("myname", password:"mypass") {
(user: PFUser?, error: NSError?) -> Void in
if user != nil {
// Do stuff after successful login.
} else {
// The login failed. Check error to see why.
}
}
The docs don't document this. I know the in keyword is used in for loops.
Anyone confirm?
In a named function, we declare the parameters and return type in the func declaration line.
func say(s:String)->() {
// body
}
In an anonymous function, there is no func declaration line - it's anonymous! So we do it with an in line at the start of the body instead.
{
(s:String)->() in
// body
}
(That is the full form of an anonymous function. But then Swift has a series of rules allowing the return type, the parameter types, and even the parameter names and the whole in line to be omitted under certain circumstances.)
Closure expression syntax has the following general form:
The question of what purpose in serves has been well-answered by other users here; in summary: in is a keyword defined in the Swift closure syntax as a separator between the function type and the function body in a closure:
{ /parameters and type/ in /function body/ }
But for those who might be wondering "but why specifically the keyword in?", here's a bit of history shared by Joe Groff, Senior Swift Compiler Engineer at Apple, on the Swift forums:
It's my fault, sorry. In the early days of Swift, we had a closure
syntax that was very similar to traditional Javascript:
func (arg: -> Type, arg: Type) -> Return { ... }
While this is nice and regular syntax, it is of course also very bulky
and awkward if you're trying to support expressive functional APIs,
such as map/filter on collections, or if you want libraries to be able
to provide closure-based APIs that feel like extensions of the
language.
Our earliest adopters at Apple complained about this, and mandated
that we support Ruby-style trailing closure syntax. This is tricky to
fit into a C-style syntax like Swift's, and we tried many different
iterations, including literally Ruby's {|args| } syntax, but many of
them suffered from ambiguities or simply distaste and revolt from our
early adopters. We wanted something that still looked like other parts
of the language, but which could be parsed unambiguously and could
span the breadth of use cases from a fully explicit function signature
to extremely compact.
We had already taken in as a keyword, we couldn't use -> like Java
does because it's already used to denote the return type, and we were
concerned that using => like C# would be too visually confusing. in
made xs.map { x in f(x) } look vaguely like for x in xs { f(x) },
and people hated it less than the alternatives.
*Formatting and emphasis mine. And thanks to Nikita Belov's post on the Swift forums for helping my own understanding.