class PersonEntry: NSObject {
var firstName: String?
var lastName: String?
}
//This errors
if (self.person.firstName?.isEmpty) {
println("Empty")
}
//Compiler auto-correction is this
if ((self.model.firstName?.isEmpty) != nil) {
println("Empty")
}
I understand that optional chaining returns an optional type. So I suppose my question is, how do you unwrap an optional string, to inspect it's length, without risking a crash ?
I presume that if the property is nil then you want to consider it empty - in that case you can use the nil coalescing operator in combination with the first version of the if statement:
if self.person.firstName?.isEmpty ?? true {
println("Empty")
}
If firstName is nil, the expression evaluates to the right side of the coalescing operator, true - otherwise it evaluates to the value of the isEmpty property.
References:
Nil Coalescing Operator
Optional Chaining
Another trick.
var str: String?
str = "Hello, playground"
println(count(str ?? ""))
Related
Hello i have array and i want to explode 1 item into it and i want to check if variable not null or null and gives me that error
Initializer for conditional binding must have Optional type, not 'String' Variable Error
My codes here.
var myStringArrctakesf = itemListcomming.components(separatedBy: ",")
if let commingtel = myStringArrctakesf[11] {
//notnull
} else {
//null
}
I want if myStringArrctakesf[11] is null dont crash app and if not null show variable.
Thanks
components(separatedBy: ) never contain nil in any of its element. Perhaps what you want is to check the myStringArrctakesf has at least 12 elements?
if myStringArrctakesf.count >= 12 {
let comingtel = myStringArrctakesf[11]
} else {
// Array didn't have enough components
}
Before Swift 2 I used this extension to check if a string only is made out of numbers:
func isNumbersOnly() -> Bool {
let regexNumbersOnly = NSRegularExpression(pattern: ".*[^0-9].*", options: nil, error: nil)!
return regexNumbersOnly.firstMatchInString(self, options: nil, range: NSMakeRange(0, self.length())) != nil
}
but now with Swift 2 I get the error
Cannot invoke initializer for type 'NSRegularExpression' with an
argument list of type '(pattern: String, options:
NilLiteralConvertible, error: NilLiteralConvertible)'
Is there a better known way now? Thnx!
In Swift 2 NSRegularExpression "throws" so you have to use it with try.
Also you can't pass nil for options anymore: if you don't want to specify options, pass an empty array (same for firstMatchInString).
And self.length() should become self.characters.count.
Last note: if the goal is to determine if a String contains only numbers, and since you're naming it "isNumbersOnly", the resulting Boolean should be true if there's only numbers: it's currently the inverse. I've fixed this in my example.
Ignoring errors:
let regexNumbersOnly = try! NSRegularExpression(pattern: ".*[^0-9].*", options: [])
return regexNumbersOnly.firstMatchInString(self, options: [], range: NSMakeRange(0, self.characters.count)) == nil
With proper error handling:
do {
let regexNumbersOnly = try NSRegularExpression(pattern: ".*[^0-9].*", options: [])
return regexNumbersOnly.firstMatchInString(self, options: [], range: NSMakeRange(0, self.characters.count)) == nil
} catch let error as NSError {
print(error.description)
}
Instead of using regular expressions, you can use CharacterSets to check for the existence (or absence) of certain characters. To check if the string is only digits you can use the following:
extension String {
var isDigits: Bool {
if isEmpty { return false }
// The inverted set of .decimalDigits is every character minus digits
let nonDigits = CharacterSet.decimalDigits.inverted
return rangeOfCharacter(from: nonDigits) == nil
}
}
This method can be applied to any type of CharacterSet and, in my opinion, is a lot cleaner than using regex strings.
Swift 2 has adjusted the error-handling process; you should now try the call, not specifying an error and be prepared to catch an exception.
E.g.
do {
let regexNumbersOnly = try NSRegularExpression(pattern: ..., options: nil)
... etc ...
} catch _ {}
... given that you're electing not to handle error states.
I'm experimenting around the idea of a simple logger that would look like this:
log(constant: String, _ variable: [String: AnyObject]? = nil)
Which would be used like this:
log("Something happened", ["error": error])
However I want to prevent misuse of the constant/variable pattern like the following:
log("Something happened: \(error)") // `error` should be passed in the `variable` argument
Is there a way to make sure that constant wasn't constructed with a string interpolation?
You could use StaticString instead of String:
func log(constant: StaticString, _ variable: [String: AnyObject]? = nil) {
// You can retrieve `String` from `StaticString`
let msg = constant.stringValue
}
let foo = 1
log("test \(foo)") // -> error: cannot invoke 'log' with an argument list of type '(String)'
If want to both assign a string and check that its not empty in Swift.
if let alternative3Text = attributes.stringForKey("choiceThree") && alternative3Text != "" {
// do stuff with alternative3Text
}
Is this possible in Swift, or do i have to do a nested if-statement?
Update: As of Swift 3 (Xcode 8), additional clauses are
separated by a comma, not by where:
if let alternative3Text = attributes.string(forKey: "choiceThree"),
alternative3Text != "" {
// do stuff with alternative3Text
}
Update: As of Swift 1.2 (Xcode 6.3 beta), you can combine
optional binding with additional conditions:
if let alternative3Text = attributes.stringForKey("choiceThree") where alternative3Text != "" {
// do stuff with alternative3Text
}
Using switch-case still works but is not necessary anymore for this purpose.
Old answer:
It is not possible with an if statement, but with switch.
A switch case can use a where clause to check for additional conditions
(documentation).
Assuming (from your question) that attributes.stringForKey("choiceThree") returns
String?, the following would work:
switch (attributes.stringForKey("choiceThree")) {
case .Some(let alternative3Text) where alternative3Text != "":
// alternative3Text is the unwrapped String here
default:
break
}
No, you can't require additional expressions to be true in an if let statement. You will need to add additional code to do this in either the form of a nested if statement as you've already mentioned, or in some other way. If your only requirement is to keep this statement looking clean and wouldn't mind moving some of the logic elsewhere, you could always make an extension to what ever type your attributes variable is to add this functionality.
Here's an example if attributes was an instance of NSUserDefaults. (just because it already contains a stringForKey() instance method.)
extension NSUserDefaults {
func nonEmptyStringForKey(key: String) -> String? {
let full = self.stringForKey(key)
return full != "" ? full : nil
}
}
And then use it like this
if let alternative3Text = attributes.nonEmptyStringForKey("choiceThree") {
// stuff
}
Let me make this clear, I have this enum:
enum Token {
Number(v:Float);
Identifier(v:String);
TString(v:String);
Var;
Assign;
Division;
// and so on
}
I want to check if the value of a variable is an Identifier, but this doesn't work:
if(tk == Token.Identifier) {
It only allows me to compare the values if I pass arguments:
if(tk == Token.Identifier('test')) {
But this will only match if the identifier is 'test', but I want to match any identifier.
Type.enumConstructor(tk) == "Identifier"
Read the Type doc for more methods on enum.
Update (2019-02-04):
At the time of writing this answer it was still Haxe 2.06. Much have changed since then.
At this moment, for Haxe 3 (or 4), I would recommend pattern matching, specifically using single pattern check instead:
if (tk.match(Identifier(_)) ...
which is a short hand for
if (switch tk { case Identifier(_): true; case _: false; }) ...
_ is the wildcard that matches anything.
alternatively:
static function isIdentifier(token : Token) return switch(token) { case Token.Identifier(_): true; default: false; }
Using "using" you should also be able to do:
if(tk.isIdentifier()) {
Or even:
tk.match(Token.Identifier(_));