How to make the closures shorter? - swift

How to make the closures shorter? I want to know the simple programming of the closures.
let closures = { (fillBefore: Bool, fillAfter: Bool) -> String in
if fillBefore && fillAfter {
return kCAFillModeBoth
} else if !fillBefore && fillAfter {
return kCAFillModeBackwards
} else if fillBefore && !fillAfter {
return kCAFillModeForwards
} else {
return kCAFillModeRemoved
}
}
anim?.fillMode = closures((item?.fillBefore)!, (item?.fillAfter)!)
How to make the closures shorter?

Based on your case, I think that at some point you have to evaluate both of booleans, so I would assume that there is no "shorter" code for handling it.
However, you might be looking for a "neater" approach, so I would suggest to evaluate them as pair of booleans (tuple), with a switch statement:
let closure = { (fillBefore: Bool, fillAfter: Bool) -> String in
switch (fillBefore, fillAfter) {
case (true, true):
return kCAFillModeBoth
case (false, true):
return kCAFillModeBackwards
case (true, false):
return kCAFillModeForwards
default: // on your case, it would be the same as (false, false)
return kCAFillModeRemoved
}
}
let myClosure = closure(false,false)
myClosure // removed

Related

How to check enum type in Swift in a more concise way?

This is how I check enum type. Is it a way not do it with switch but shorter?
if let i = instance as? DataToValidate {
switch i {
case .object:
return true
default:
return false
}
} else {
return false
}
And my type:
public enum DataToValidate {
case object(JSONObject)
case array(JSONArray)
case string(String)
}
The if and guard statements allow you to use pattern matching.
if case DataToValidate.object = instance {
return true
} else {
return false
}
If you want to use the associated value, you can bind it:
if case DataToValidate.object(let object) = instance {
return object
} else {
return nil
}
Most succinct now:
if case DataToValidate.object = instance {
return true
}
return false
Might become better:
instance is case DataToValidate.object

"Expression type 'Bool' is ambiguous without more context" in ternary operation

I am trying to pass an enum to a function that does an operation on that enum's arguments. I receive this error:
Expression type 'Bool' is ambiguous without more context
The same error happens in an equivalent if clause, so it's not the ternary operator itself that causes the problem.
enum auto {
case pkw (SerialNumber: String, Axles: Int, Weight: Float)
case lkw (SerialNumber: String, Axles: Int, Weight: Float)
}
func checkIntegrity(car: auto) -> Bool {
switch car {
case .pkw:
if (checkSerialNumber(serialNumber: .pkw.SerialNumber.rawValue)
&& checkWeight(weight: .pkw.Weight.rawValue)) { // Error here, "&&" is underlined
return true
} else {
return false
}
break;
case .lkw:
return (checkSerialNumber(serialNumber: .lkw.SerialNumber.rawValue)
&& checkWeight(weight: .lkw.Weight.rawValue)) ? true : false; // same error here, "&&" is underlined
break;
default:
return false
}
The other functions that are called just return a Bool:
func checkSerialNumber(serialNumber: String) -> Bool {
return serialNumber.contains("ABABWA") // changed after a hint in the comments
}
func checkWeight(weight: Float) -> Bool {
return (weight < 2)
}
I am suspecting something wrong with the enum and how I use them, but I haven't found the solution yet.
The error message is misleading. You want to check the associated values
of an enumeration value, therefore you must bind those in the case pattern:
func checkIntegrity(car: auto) -> Bool {
switch car {
case let .pkw(serialNumber, _, weight):
if checkSerialNumber(serialNumber: serialNumber)
&& checkWeight(weight: weight) {
return true
} else {
return false
}
break;
case let .lkw(serialNumber, _, weight):
return (checkSerialNumber(serialNumber: serialNumber)
&& checkWeight(weight: weight)) ? true : false;
break;
default:
return false
}
}
This can be simplified to
func checkIntegrity(car: auto) -> Bool {
switch car {
case let .pkw(serialNumber, _, weight),
let .lkw(serialNumber, _, weight):
return checkSerialNumber(serialNumber: serialNumber) && checkWeight(weight: weight)
}
}

Enum pattern matching as a parameter to a function call

I've setup a playground with an example:
enum CarType : Equatable {
case wheeled(wheels: Int)
case flying
public static func ==(lhs: CarType, rhs: CarType) -> Bool {
return lhs.enumName == rhs.enumName
}
var enumName: String {
let stuff = "\(self)".split(separator: "(").first!
return String(describing: stuff)
}
}
var typesPresentAtMyParty = [CarType.wheeled(wheels:4), .wheeled(wheels:4), .flying]
let aKnownType = CarType.flying
if case aKnownType = typesPresentAtMyParty[2] {
print("Was the type")
}
func isPresent(type: CarType, inArray: [CarType]) -> Bool {
return inArray.filter {
if case type = $0 {
return true
}
return false
}.first != nil
}
func isWheeled(inArray: [CarType]) -> Bool {
return inArray.filter {
if case .wheeled = $0 {
return true
}
return false
}.first != nil
}
isPresent(type: .flying, inArray: typesPresentAtMyParty)
isPresent(type: .wheeled, inArray: typesPresentAtMyParty)
The last line here does not compile. While i can do if case .wheeled = $0 ignoring associated type as a check, i cannot find a way of doing the same in a function call isPresent(type: CarType, inArray: [CarType]), when sending isPresent(type: .wheeled, inArray: typesPresentAtMyParty)
Is there a way of writing a function that takes only the valid pattern matching part of the enum as a parameter?
It is not possible to pass partially constructed enums to a function. Partially constructed enums are not valid values, and they only work in pattern matching because the compiler has a concrete value to work with - the one from the right side of the pattern.
These being said, you could easily rewrite your functions to better, more swiftier versions.
Firstly, you don't need isPresent, you can simply use contains:
typesPresentAtMyParty.contains { $0 == .flying }
typesPresentAtMyParty.contains { if case . wheeled = $0 { return true } else { return false } }
Similarly, isWheeled can be shortened (and renamed, for better semantics):
func isWheeled(_ carType: CarType) -> Bool {
if case . wheeled = carType { return true } else { return false }
}
which can pe passed to contains:
let hasWeeled = typesPresentAtMyParty.contains(where: isWheeled)

How to get a case of enum in one line?

I have a enum with some case, and a array with instances of this enum, for example:
enum MyEnum {
case foo(Int)
case bar(Int)
case baz(Int)
}
let myArray = [
MyEnum.foo(1),
MyEnum.bar(2),
MyEnum.baz(3)
]
Then, I need to compare if determinate element of this array if foo, baz or baz, for example:
myArray.filter { $0 == .foo } // not work, and should need return [MyEnum.foo(1)]
I can use switch:
myArray.filter {
switch $0 {
case .foo(_):
return true
default:
return false
}
} // work, and return [MyEnum.foo(1)]
But, I want a solution less verbose, and learning more about enum.
The shortest I can think of is:
let result = myArray.filter { if case .foo = $0 { return true } else { return false } }
As mentioned before if case is a good solution since swift 2.0. But if you're going to use this same filter many times, then you will need a more expressive way to do this. For instance, you can make this enum equatable hiding your switchCase away from the viewController:
extension MyEnum: Equatable{
static func ==(lhs: MyEnum, rhs: MyEnum) -> Bool{
switch (lhs, rhs) {
case (.foo(_), .foo(_)):
return true
case (.bar(_), .bar(_)):
return true
case (.baz(_), .baz(_)):
return true
default:
return false
}
}
}
and then:
myArray.filter {
$0 == .foo(1)
}
If you really want to do it in one line, you can use reflection:
myArray.filter { Mirror(reflecting: $0).children.first!.label! == "foo" }

Evaluating Swift's Bool? for true/false/nil in one line?

I've got a lot of code like this:
if let x = optbool {
return f(x)
} else {
return false
}
Can this be expressed on a single line?
The following statement is equivalent to your code:
return optbool.map(f) ?? false
If optbool == nil then .map(f) returns nil,
and the nil-coalescing operator ?? false changes that
to false.
If optbool != nil then .map(f) returns f(optbool!),
which is also the result of the nil-coalescing operator.
Try this:
return optbool != nil ? f(optbool!) : false
your code is valid only if func f(x:Bool)->Bool
func foo(b: Bool?)-> Bool {
if let x = b {
return f(x)
} else {
return false
}
}
now the question has no logic more ... and you can use one of this
let res1 = f(b ?? false)
let res2 = f(b ?? true)
let res3 = !f(b ?? false)
let res4 = !f(b ?? true)
depending on your f function
If you define the f function as an extension of Bool:
extension Bool {
func f() -> Bool {
return true // or false..
}
}
then you can write
return x?.f() ?? false
or
return x?.f() == true
If your question is really:
Can this be expressed on a single line?
The answer is undoubtedly YES:
if let x = optbool { return f(x) } else { return false }
;-)
Seriously, if optbool is not supposed to be nil, I would rather write it on 2 lines:
guard let x = optbool else { return false }
return f(x)