.rangeOfString() with switch in Swift - ios

I want to check if my input has a rangeOfString must with a lot of different strings to check.
basically this if statement but using a switch to check a big list of different strings
if (input.rangeOfString("lol") != nil) {
println("yes")
}
I've tried doing this but it isn't working.
switch input {
case rangeOfString("lol"):
println("lol")
case rangeOfString("dw"):
println("dw")
default:
println("Default")
}

You misunderstood the idea of a switch statement. It checks the value of one expression against multiple possible values, and optionally lets you access associated values of an enumeration. It does not let you pass a single value to multiple expressions listed as switch cases*, and pick whichever provides the first match.
You need to make a chain of if-elses to make your code work:
if (input.rangeOfString("lol") != nil) {
println("lol")
} else if (input.rangeOfString("dw") != nil) {
println("dw")
} else {
println("Default")
}
I would like to check if a word is being used in the input and I have like 50 words I'd like to check.
Then the switch is not a good alternative either. Make a container of the words you wish to search, and use filter to find all matches:
let input = "hahalolblah"
let words = ["lol", "blah", "hello"];
let matches = words.filter {input.rangeOfString($0) != nil}
println(matches) // Produces [lol, blah]
* It turns out that switch lets you pass one expression to an override of the ~= operator, along with values coming from cases of the switch. See this answer for details.

While the others answers are probably right about if being a better way to go, you can do something like this via heroic abuse of the ~= operator:
import Foundation
struct Substring {
let substr: String
init(_ substr: String) { self.substr = substr }
}
func ~=(substr: Substring, str: String) -> Bool {
return str.rangeOfString(substr.substr) != nil
}
let input = "contains wat"
switch input {
case Substring("lol"), Substring("wat"):
println("huh?") // this one is picked
case Substring("dw"):
println("dw")
// you can also mix and match
case "Explicit full string":
println("matches whole string")
default:
println("Default")
}
Switch statements in Swift can be extended via overloading of the ~= operator. So for example, the reason this works:
switch 2.5 {
case 0...5: println("between nought and five")
default: println("not in range")
}
is because there is a definition of the ~= operator that matches any kind of Comparable type to an interval:
func ~=<I : IntervalType>(pattern: I, value: I.Bound) -> Bool
Here, by creating a new type of Substring, I've created a way to match strings to substrings.
In theory you could skip the creation of the Substring type and do the following:
func ~=(substr: String, str: String) -> Bool {
return str.rangeOfString(str) != nil
}
let input = "contains lol"
switch input {
case "lol":
println("lol")
case "dw":
println("dw")
default:
println("Default")
}
This would work, but would be a bad idea because now you'll have changed the way switches on strings work universally so that partial matches are always true, which could lead to some unpleasant and unexpected behaviour elsewhere in your code.

You can also do something like:
switch true {
case myString.rangeOfString("lol") != nil:
print("lol");
case myString.rangeOfString("dw") != nil:
print("dw");
default:
print("Default")
}

Related

How to I cast a type to a variable in an enum within a switch statement?

switch error {
case Project.Client.LoadError.operationFailed(let error2):
switch error2 {
case Project.Client.APIClientError.invalidStatusCode(let message, _):
guard message != nil, message == "error" else {
return refresh()
}
delegate?.error(invalidScript)
default:
refresh()
}
default:
refresh()
}
Here is my current code. This works but I feel there is a better way to do this.
How can I make error2 NOT go through another switch statement and just cast it as an invalidStatusCode that I can use?
Or, what terms can I search up to better understand what is happening here/understand what to look up myself for the answer?
As I might not be fully understanding switch statements as casting type.
Thank you in advance.
Pattern matching of enums with associated values is composable, so you can do this:
switch error {
case Project.Client.LoadError.operationFailed(Project.Client.APIClientError.invalidStatusCode("error" , _)):
delegate?.error(invalidScript)
default:
refresh()
}
You might notice that this is a bit hard to read because of how long these fully-qualified type-names are.
I suspect the type of error is the general Error, but in other cases, if the type of error is already-known to be Project.Client.LoadError, then you can just use .operationFailed (leaving the type to be inferred from context). And if .operationFailed's associated type is known to have type Project.Client.APIClientError, you can just use .invalidStatusCode.
If not, you can use some local type-aliases can help with that:
typealias LoadError = Project.Client.LoadError
typealias APIClientError = Project.Client.APIClientError
switch error {
case LoadError.operationFailed(APIClientError.invalidStatusCode("error", _)):
delegate?.error(invalidScript)
default:
refresh()
}
Since you are just drilling down to one case for both switches, you don't need any switches at all. You can use if case instead. To generalize, suppose we have this:
enum Outer {
case inner(Inner)
case other
}
enum Inner {
case message(String)
case other
}
Now suppose subject might be an Outer. Then to determine that this is an Outer's .inner case whose Inner value is .message and that message's value is "howdy", we can say:
if case Outer.inner(let inner) = subject,
case Inner.message(let message) = inner,
message == "howdy" {

Return a random case from an enum in Swift

I just wrote a function that generates a random integer in a range of 0...2. The goal is to return a random case from an enum based on the random integer.
I'd like to prefer to use the case statement but I don't like the default case which returns an arbitrary enum. Omitting the default case will not work since switch is not able to know how much cases will occur. Even though the default case would never happen I don't consider this to be a clean solution.
Which solution would you prefer respectively consider to be the cleanest solution - please elaborate. Is there a better/more elegant way to return a random case from an enum?
If-else solution:
func generateRandomSign() -> Sign {
let randomSelection = Int.random(in: 0...2)
if randomSelection == 0 {
return .rock
} else if randomSelection == 1 {
return .paper
}
return .scissor
}
Switch solution:
func generateRandomSign() -> Sign {
let randomSelection = Int.random(in: 0...2)
switch randomSelection {
case 0: return .rock
case 1: return .paper
case 2: return .scissor
default: return .rock
}
}
There's no need for messing around with Ints. You should rather declare your Sign enum to conform to CaseIterable and call randomElement() on its allCases property (which as its name suggests, contains all cases of the enum).
This way you don't sacrifice type safety and you're guaranteed to get back a case of Sign every time.
enum Sign: CaseIterable {
case rock
case paper
case scissor
static func random() -> Sign {
return allCases.randomElement()! // safe to force unwrap, since the enum has at least 1 property, so this can never be `nil`
}
}
You can call it like let randomSign = Sign.random()

confused with the functionality of `return` in swift

I am confused with return in Swift. I understand it's used to return the value in a function, if used like this:
func double(value: int) -> Int {
return value * 2
}
But I often just see return being used, like in a guard statement in an optional binding like this:
guard let value = value else (
print ("nothing")
return
}
So what is the purpose of having just return in the guard statement like this? Actually, I often see this not only in guard statements when unwrapping optional values. I always find this problem when writing code, when I want to use an optional string from a dictionary.
let info = ["name": "sarah", "hometown": "sydney"]
class UserInfo {
func getTheName() -> String {
guard let name = info["name"] else { return }
return name
}
}
// Compile time error: "Non-void function should return a value"
I get this error even though I have written return name. Xcode still complains that I have not returned a value. Is it because of the return in the guard statement?
So, could you please tell me the purpose of return in Swift? It is confusing for me.
return without any argument returns Void. This form of the return statement can only be used with a function that returns Void.
Once the return statement executes, the function exits and no more code in your function executes. Since you have a return in the guard statement, the second return name won't be executed (it couldn't anyway since it wouldn't have a name to return), which is why you get a compiler error; the compiler looks at all of the paths that your function could take to return something and ensures that all of those paths return what the function signature says it will.
The function in your question states that it returns a String, so you can't simply say return in the guard statement as that returns Void, violating the contract expressed by your function signature.
You could return a default value that isn't Void:
func getTheName () -> String {
guard let name = info["name"] else {
return ""
}
return name
}
This could be written much more succinctly using the nil-coalescing operator; return info["name"] ?? ""
You can also use return in a function that returns Void (or has no explicit return type, in which case it is implicitly understood to return Void)
So you could have a function like:
func maybePrint(theMessage: String?) -> Void {
guard let msg = theMessage else {
return
}
print(msg)
}
You're on the right track.
In your guard statement inside getTheName(), the 'return' keyword will try to exit the function itself if the guard fails. But the function requires you to return a String and as such you get the compiler error.
Here is a portion of another SO answer to a similar question:
guard forces you to exit the scope using a control transfer statement.
There are 4 available to you:
return and throw both exit the function/method continue can be used
within loops (while/for/repeat-while) break can be used in loops
(while/for/repeat-while) to exit the immediate scope. Specifying a
label to break to will allow you to exit multiple scopes at once (e.g.
breaking out of nested loop structure). When using a label, break can
also be used in if scopes. Additionally, you may exit the scope by
calling a function that returns Never, such as fatalError.
Stack Overflow: If the Swift 'guard' statement must exit scope, what is the definition of scope?

Can I somehow use optional binding for multiple variables in one line in Swift? [duplicate]

This question already has answers here:
Using "if let..." with many expressions
(3 answers)
Closed 8 years ago.
Can I somehow use optional binding for multiple variables in one line in Swift? I need to do something like this:
if let foo = fooOptional && let bar = barOptional {
// ...
}
Update for Swift 1.2:
From Swift 1.2 (Xcode 6.3 Beta), you can unwrap multiple optionals with if let:
if let foo = fooOptional, bar = barOptional {
println("\(foo), \(bar)")
}
Before Swift 1.2
You cannot with if, but you can with switch using "Value-Binding Pattern":
switch (fooOptional, barOptional) {
case let (.Some(foo), .Some(bar)):
println("\(foo), \(bar)")
default:
break
}
It's a little clunky, but you can do this with a switch on a tuple of your variables:
var fooOptional: String? = "foo"
var barOptional: String? = "bar"
switch (fooOptional, barOptional) {
case let (.Some(foo), .Some(bar)):
println(foo + bar)
default:
break
}
The time I use this is drilling down into a nested dictionary, like a big JSON object -- it's great because you can handle each error case separately:
switch (dict["foo"], dict["foo"]?["bar"], dict["foo"]?["bar"]?["baz"]) {
case let (.Some(foo), .Some(bar), .Some(baz)):
// do things
case (.None, _, _):
// no foo
case (_, .None, _):
// no bar
default:
// no baz
}
Before Swift 1.2
I like using the switch statement for this, especially if you want to handle the four different cases.
However, if you're merely interested in the case where both optionals are Some, you can also do this:
if let (firstName, lastName) = unwrap(optionalFirstName, optionalLastName) {
println("Hello \(firstName) \(lastName)!")
}
Where this is the definition of the unwrap function:
func unwrap<T1, T2>(optional1: T1?, optional2: T2?) -> (T1, T2)? {
switch (optional1, optional2) {
case let (.Some(value1), .Some(value2)):
return (value1, value2)
default:
return nil
}
}
More overloads: https://gist.github.com/tomlokhorst/f9a826bf24d16cb5f6a3

Swift: Testing optionals for nil

I'm using Xcode 6 Beta 4. I have this weird situation where I cannot figure out how to appropriately test for optionals.
If I have an optional xyz, is the correct way to test:
if (xyz) // Do something
or
if (xyz != nil) // Do something
The documents say to do it the first way, but I've found that sometimes, the second way is required, and doesn't generate a compiler error, but other times, the second way generates a compiler error.
My specific example is using the GData XML parser bridged to swift:
let xml = GDataXMLDocument(
XMLString: responseBody,
options: 0,
error: &xmlError);
if (xmlError != nil)
Here, if I just did:
if xmlError
it would always return true. However, if I do:
if (xmlError != nil)
then it works (as how it works in Objective-C).
Is there something with the GData XML and the way it treats optionals that I am missing?
In Xcode Beta 5, they no longer let you do:
var xyz : NSString?
if xyz {
// Do something using `xyz`.
}
This produces an error:
does not conform to protocol 'BooleanType.Protocol'
You have to use one of these forms:
if xyz != nil {
// Do something using `xyz`.
}
if let xy = xyz {
// Do something using `xy`.
}
To add to the other answers, instead of assigning to a differently named variable inside of an if condition:
var a: Int? = 5
if let b = a {
// do something
}
you can reuse the same variable name like this:
var a: Int? = 5
if let a = a {
// do something
}
This might help you avoid running out of creative variable names...
This takes advantage of variable shadowing that is supported in Swift.
Swift 3.0, 4.0
There are mainly two ways of checking optional for nil. Here are examples with comparison between them
1. if let
if let is the most basic way to check optional for nil. Other conditions can be appended to this nil check, separated by comma. The variable must not be nil to move for the next condition. If only nil check is required, remove extra conditions in the following code.
Other than that, if x is not nil, the if closure will be executed and x_val will be available inside. Otherwise the else closure is triggered.
if let x_val = x, x_val > 5 {
//x_val available on this scope
} else {
}
2. guard let
guard let can do similar things. It's main purpose is to make it logically more reasonable. It's like saying Make sure the variable is not nil, otherwise stop the function. guard let can also do extra condition checking as if let.
The differences are that the unwrapped value will be available on same scope as guard let, as shown in the comment below. This also leads to the point that in else closure, the program has to exit the current scope, by return, break, etc.
guard let x_val = x, x_val > 5 else {
return
}
//x_val available on this scope
One of the most direct ways to use optionals is the following:
Assuming xyz is of optional type, like Int? for example.
if let possXYZ = xyz {
// do something with possXYZ (the unwrapped value of xyz)
} else {
// do something now that we know xyz is .None
}
This way you can both test if xyz contains a value and if so, immediately work with that value.
With regards to your compiler error, the type UInt8 is not optional (note no '?') and therefore cannot be converted to nil. Make sure the variable you're working with is an optional before you treat it like one.
From swift programming guide
If Statements and Forced Unwrapping
You can use an if statement to find out whether an optional contains a
value. If an optional does have a value, it evaluates to true; if it
has no value at all, it evaluates to false.
So the best way to do this is
// swift > 3
if xyz != nil {}
and if you are using the xyz in if statement.Than you can unwrap xyz in if statement in constant variable .So you do not need to unwrap every place in if statement where xyz is used.
if let yourConstant = xyz {
//use youtConstant you do not need to unwrap `xyz`
}
This convention is suggested by apple and it will be followed by devlopers.
Although you must still either explicitly compare an optional with nil or use optional binding to additionally extract its value (i.e. optionals are not implicitly converted into Boolean values), it's worth noting that Swift 2 has added the guard statement to help avoid the pyramid of doom when working with multiple optional values.
In other words, your options now include explicitly checking for nil:
if xyz != nil {
// Do something with xyz
}
Optional binding:
if let xyz = xyz {
// Do something with xyz
// (Note that we can reuse the same variable name)
}
And guard statements:
guard let xyz = xyz else {
// Handle failure and then exit this code block
// e.g. by calling return, break, continue, or throw
return
}
// Do something with xyz, which is now guaranteed to be non-nil
Note how ordinary optional binding can lead to greater indentation when there is more than one optional value:
if let abc = abc {
if let xyz = xyz {
// Do something with abc and xyz
}
}
You can avoid this nesting with guard statements:
guard let abc = abc else {
// Handle failure and then exit this code block
return
}
guard let xyz = xyz else {
// Handle failure and then exit this code block
return
}
// Do something with abc and xyz
Swift 5 Protocol Extension
Here is an approach using protocol extension so that you can easily inline an optional nil check:
import Foundation
public extension Optional {
var isNil: Bool {
guard case Optional.none = self else {
return false
}
return true
}
var isSome: Bool {
return !self.isNil
}
}
Usage
var myValue: String?
if myValue.isNil {
// do something
}
if myValue.isSome {
// do something
}
One option that hasn't specifically been covered is using Swift's ignored value syntax:
if let _ = xyz {
// something that should only happen if xyz is not nil
}
I like this since checking for nil feels out of place in a modern language like Swift. I think the reason it feels out of place is that nil is basically a sentinel value. We've done away with sentinels pretty much everywhere else in modern programming so nil feels like it should go too.
Instead of if, ternary operator might come handy when you want to get a value based on whether something is nil:
func f(x: String?) -> String {
return x == nil ? "empty" : "non-empty"
}
Another approach besides using if or guard statements to do the optional binding is to extend Optional with:
extension Optional {
func ifValue(_ valueHandler: (Wrapped) -> Void) {
switch self {
case .some(let wrapped): valueHandler(wrapped)
default: break
}
}
}
ifValue receives a closure and calls it with the value as an argument when the optional is not nil. It is used this way:
var helloString: String? = "Hello, World!"
helloString.ifValue {
print($0) // prints "Hello, World!"
}
helloString = nil
helloString.ifValue {
print($0) // This code never runs
}
You should probably use an if or guard however as those are the most conventional (thus familiar) approaches used by Swift programmers.
Optional
Also you can use Nil-Coalescing Operator
The nil-coalescing operator (a ?? b) unwraps an optional a if it contains a value, or returns a default value b if a is nil. The expression a is always of an optional type. The expression b must match the type that is stored inside a.
let value = optionalValue ?? defaultValue
If optionalValue is nil, it automatically assigns value to defaultValue
Now you can do in swift the following thing which allows you to regain a little bit of the objective-c if nil else
if textfieldDate.text?.isEmpty ?? true {
}
var xyz : NSDictionary?
// case 1:
xyz = ["1":"one"]
// case 2: (empty dictionary)
xyz = NSDictionary()
// case 3: do nothing
if xyz { NSLog("xyz is not nil.") }
else { NSLog("xyz is nil.") }
This test worked as expected in all cases.
BTW, you do not need the brackets ().
If you have conditional and would like to unwrap and compare, how about taking advantage of the short-circuit evaluation of compound boolean expression as in
if xyz != nil && xyz! == "some non-nil value" {
}
Granted, this is not as readable as some of the other suggested posts, but gets the job done and somewhat succinct than the other suggested solutions.
If someone is also try to find to work with dictionaries and try to work with Optional(nil).
let example : [Int:Double?] = [2: 0.5]
let test = example[0]
You will end up with the type Double??.
To continue on your code, just use coalescing to get around it.
let example : [Int:Double?] = [2: 0.5]
let test = example[0] ?? nil
Now you just have Double?
This is totally logical, but I searched the wrong thing, maybe it helps someone else.
Since Swift 5.7:
if let xyz {
// Do something using `xyz` (`xyz` is not optional here)
} else {
// `xyz` was nil
}

Resources