So I fail to figure a 1 liner for following syntax in Swift and it is driving me nuts:
if lastProfile == nil || lastProfile.id == profile.id {
useProfile(profile)
lastProfile = profile
}
Now see I could chain it but I'd still end up with 2-3 ifs. I could pack it out but then I again end up with 2-3 ifs... Is it possible to do this in just 1 swoop?
Edit:
My colleague found an alternative (although we agree ugly):
if !(latestProfile != nil && latestProfile!.voiceId != profile.voiceId) {
}
Is there a better approach than above?
Solution is just a ? away:
if lastProfile == nil || lastProfile?.id == profile.id {
print("true")
lastProfile = profile
}
This prints "true" when lastProfile is nil or when lastProfile and profile have the same id. Otherwise it prints nothing.
If lastProfile is declared as let lastProfile: Profile? = ..., and for example id is declared as optional also you can use it as:
if let lastProfileId = lastProfile?.id {
// lastProfile is not nil and id is not nil
}
else {
// lastProfile is nil or lastProfile.id is nil
}
It is called Optional Chaining and you can read about it on swift docs.
if let recentProfile = latestProfile where recentProfile.voieId != profile.voiceId {
useProfile(profile)
lastProfile = profile
}
Related
I am going through old code from HomeKit Catalog: Creating Homes, Pairing and Controlling Accessories, and Setting Up Triggers when I ran into an expression that says
.KeyPathExpressionType
I can't tell what the
.
in
.KeyPathExpressionType
is referring to on the left side of the
.
I find nothing when I search Google and stackoverflow for "KeyPathExpressionType". It's the same with
.ConstantValueExpressionType
I find nothing.
Each of those equality comparisons
comparison.leftExpression.expressionType == .KeyPathExpressionType
and
comparison.rightExpression.expressionType == .ConstantValueExpressionType
in the code below, generate an error message that says:
Binary operator '==' cannot be applied to operands of type 'NSExpression.ExpressionType' and '_'
extension NSPredicate {
/**
Parses the predicate and attempts to generate a characteristic-value `HomeKitConditionType`.
- returns: An optional characteristic-value tuple.
*/
private func characteristic() -> HomeKitConditionType? {
guard let predicate = self as? NSCompoundPredicate else { return nil }
guard let subpredicates = predicate.subpredicates as? [NSPredicate] else { return nil }
guard subpredicates.count == 2 else { return nil }
var characteristicPredicate: NSComparisonPredicate? = nil
var valuePredicate: NSComparisonPredicate? = nil
for subpredicate in subpredicates {
if let comparison = subpredicate as? NSComparisonPredicate, comparison.leftExpression.expressionType == .KeyPathExpressionType && comparison.rightExpression.expressionType == .ConstantValueExpressionType {
switch comparison.leftExpression.keyPath {
case HMCharacteristicKeyPath:
characteristicPredicate = comparison
case HMCharacteristicValueKeyPath:
valuePredicate = comparison
default:
break
}
}
}
if let characteristic = characteristicPredicate?.rightExpression.constantValue as? HMCharacteristic,
characteristicValue = valuePredicate?.rightExpression.constantValue as? NSCopying {
return .Characteristic(characteristic, characteristicValue)
}
return nil
}
I get the error to go away when I replace
comparison.leftExpression.expressionType == .KeyPathExpressionType
with
comparison.leftExpression.expressionType.rawValue == NSExpression.ExpressionType.keyPath.rawValue
and
comparison.rightExpression.expressionType == .ConstantValueExpressionType
with
comparison.rightExpression.expressionType.rawValue == NSExpression.ExpressionType.constantValue.rawValue
Is this correct? Can anyone tell me enlighten me on this problem?
The code is outdated Swift 2 code.
Replace .KeyPathExpressionType with .keyPath and .ConstantValueExpressionType with .constantValue
The type is NSExpression.ExpressionType, please read the documentation
Please consider following:
let isHaveSn = model.positions.contains {$0.assortment?.isSerialTrackable == true}
guard isHaveSn else {
return
}
isHaveSn product Bool, and so i check that Bool in guard and everything work. But i want to simplify this like that:
guard model.positions.contains {$0.assortment?.isSerialTrackable == true} else {
return
}
It produce several errors, some of them: expected expression or Consecutive statement should be separated by ;
But i just copy right side of:
let isHaveSn = model.positions.contains {$0.assortment?.isSerialTrackable == true}
Why my code not compile?
The correct syntax for that would be:
guard model.positions.contains(where: {$0.assortment?.isSerialTrackable == true}) else {
return
}
Actually there was a proposal in swift-evolution to enable trailing closures in guard statements that was rejected. You can read more about it here
I am trying to do something that would logically look like this:
if text == "" || let i = Int(text) where i < 2 {
// do something; don't care about the value of i
}
Of course this isn't a valid condition -- what would the value of i be if text == "" is the part that holds? But, since I'm only interested in the value of i inside the where clause, I was hoping there is a nice way of achieving the same effect, namely executing the same closure if either condition holds. My current solution is to extract the closure and call it from two separate if blocks, but that's pretty hairy-looking.
The equivalent to your code example would be:
if text == "" || Int(text) ?? 2 < 2 {
print("valid")
// do your previous "something
} else {
print("invalid")
}
which yields
"" -> valid
"1" -> valid
"2" -> invalid
"abc" -> invalid
If you're doing this kind of comparison regularly, you could create your own operator in order to compare an optional with a given closure representing your condition for success. If the unwrapped value meets the condition, it'll return true – else false.
For example:
infix operator ?& {precedence 130 }
func ?&<T>(lhs: T?, #noescape rhs:(T)->Bool) -> Bool {
return lhs != nil ? rhs(lhs!) : false
}
...
if text == "" || Int(text) ?& {$0 < 2} {
print("valid")
} else {
print("invalid")
}
You could also overload the existing < operator to do this, but this may impact already existing code that relies on nil being less than a non-optional value.
func <<T:Comparable>(lhs: T?, rhs:T) -> Bool {
return lhs != nil ? (lhs! < rhs) : false
}
...
if text == "" || Int(text) < 2 {
print("valid")
} else {
print("invalid")
}
Perhaps a more "Swifty" way to handle optional values is with map. Essentially, mapping an optional value gives you an unwrapped value in your closure, which you can then modify to return what you need. Outside the closure, you will receive either the modified value, or nil if the original optional was nil.
let optInt: Int? = 1 // or nil
let incremented: Int? = optInt.map { $0 + 1 }
// If optInt isn't nil, its incremented value is returned by map.
// If it is nil, map just returns nil.
So to solve my problem, I could do:
if text == "" || Int(text).map({$0 < 2}) ?? false {
// If text has an Int value, the map closure will return
// whether that value is less than 2.
// Else, map will return nil, which we coalesce to false.
}
I am trying to check if a textbox has no value.
When I do this:
if(userEmail?.isEmpty || userPassword?.isEmpty || userPasswordRepeat?.isEmpty)
I get the following error
I tried adding "?" before the ".isEmpty" but the error won't go away
Any ideas?
Try this....
if txtEmail.text?.isEmpty == true || txtPassword.text?.isEmpty == true || txtRePassword.text?.isEmpty == true{
print("true")
}
If interested also in positive case, the following is an alternative solution for Swift 2:
let email = self.txtEmail.text where !email.isEmpty, let password = self.txtPassword.text where !password.isEmpty {
//all fields are not nil && not empty
}else{
//some field is nil or empty
}
I have a controller that will have a variable number of textfields. On a button press I want to check for the existence of, whether or not its empty, and check the character count of the input.
I'm trying the following, which works fine if homePhone exists
if homePhone?.text != ""{
if countElements(homePhone1.text) != 10{
validInput = false
validationError = "Home Phone must be 10 digits"
}
}
But when a textfield does not exist (mobile) I get a fatal error
if mobilePhone?.text != ""{
if countElements(mobilePhone.text) != 10{
validInput = false
validationError = "Mobile Phone must be 10 digits"
}
}
fatal error: unexpectedly found nil while unwrapping an Optional value
Obviously I'm not doing the check correctly, optionals and unwrapping is continually tripping me up.
You can unwrap your textfield and check if it exists:
if let mobilePhoneField = mobilePhone{
if mobilePhoneField.text != ""{
if countElements(mobilePhoneField.text) != 10{
validInput = false
validationError = "Mobile Phone must be 10 digits"
}
}
}
This will check if your optional variable is nil or not so you can safely unwrap it, actualy it will do it for you.
if let value = myOptionalVariable{
//my optionalVariable is not nill i can do whatever i want
value.text = "Yaay"
}