Swift ignoring parameter types defined in block signature - swift

I have the code below, which the compiler is happy with:
func CheckPaintExists(colorCode : String, applicationCode : String) {
let checkRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Paint")
checkRequest.predicate = NSPredicate(block: { (item, bindings) -> Bool in
return (item as! Paint).ColorCode == colorCode
&& (item as! Paint).ApplicationCode == applicationCode
})
checkRequest.includesSubentities = false;
//managedContext.count(for: ...)do further stuff
}
But once I define the item type in the block signature, I get an error on the return line:
func CheckPaintExists2(colorCode : String, applicationCode : String) {
let checkRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Paint")
checkRequest.predicate = NSPredicate(block: { (item : Paint?, bindings : NSDictionary?) -> Bool in
return item.ColorCode == colorCode //*Value of type 'Any?' has no member 'ColorCode'
&& item.ApplicationCode == applicationCode
})
checkRequest.includesSubentities = false;
//managedContext.count(for: ...)do further stuff
}
It says Value of type 'Any?' has no member 'ColorCode'. How can I resolve this? Why is it still using the default Any type provided by the block?

If you look at the signature for NSPredicate.init(block:) then you will see that block takes two parameters and returns a boolean: (Any?, [String : Any]?) -> Bool) and the first parameter is indeed an Any.
In your first example you are force casting with as! which is why it works (it would crash here if the type was not actually Paint boxed in an Any. Your second example is giving you an error because your type annotation is wrong; the compiler expects the first parameter to be Any and not Paint?; it really should be giving you the error on the line above but it seems its first catching it on the line with the return.
If you want to unwrap safely it should be:
func CheckPaintExists(colorCode : String, applicationCode : String) {
let checkRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Paint")
checkRequest.predicate = NSPredicate(block: { (item, bindings) -> Bool in
guard let paint = item as? Paint else {
return false
}
return paint.ColorCode == colorCode
&& paint.ApplicationCode == applicationCode
})
checkRequest.includesSubentities = false;
//managedContext.count(for: ...)do further stuff
}

Related

How to get list of elements of two sequences using Set.intersection

I'm studying The Swift Programming Language (Swift 4.2)
https://docs.swift.org/swift-book/GuidedTour/GuidedTour.html
Is it possible to write a generic function to return the common elements of any two Sequences using Set.intersection()? I've written the following method (I'm a C# developer just learning, so please excuse bad Swift coding practices), but is it possible to do this without knowing the element type?
func getCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Array<Any>
where T.Element: Equatable, T.Element == U.Element
{
if let lhsSet = lhs as? Set<String> {
if let rhsSet = rhs as? Set<String> {
return Array(lhsSet.intersection(rhsSet))
}
} else if let lhsSet = lhs as? Set<Double> {
if let rhsSet = rhs as? Set<Double> {
return Array(lhsSet.intersection(rhsSet))
}
} else if let lhsArray = lhs as? Array<String> {
if let rhsArray = rhs as? Array<String> {
let lhsSet = Set<String>(lhsArray)
let rhsSet = Set<String>(rhsArray)
return Array(lhsSet.intersection(rhsSet))
}
}
return [T.Element]()
}
getCommonElements(["FirstName", "MiddleName", "LastName"], ["FirstName", "LastName"])
let elementsSet1 = Set<Double>([1.2, 2.4, 3.6])
let elementsSet2 = Set<Double>([1.2, 3.6])
getCommonElements(elementsSet1, elementsSet2)
Yes, you can even just init a Set from the input anyway. Doesn't matter if it is Set or Array since your input is Sequence and Set can be init from Sequence. where T.Element: Hashable, T.Element == U.Element already guarantee the element types are the same and can be made as Set
func getCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> [T.Element]
where T.Element: Hashable, T.Element == U.Element
{
return Array(Set<T.Element>(lhs).intersection(Set<U.Element>(rhs)))
}
print(getCommonElements(["FirstName", "MiddleName", "LastName"], ["FirstName", "LastName"]))
let elementsSet1 = Set<Double>([1.2, 2.4, 3.6])
let elementsSet2 = Set<Double>([1.2, 3.6])
print(getCommonElements(elementsSet1, elementsSet2))
output:
["FirstName", "LastName"]
[1.2, 3.6]

swift affect value to inout generic variable

I want to simplify this piece of code with a T variable but could not succeed in compiling it. Hope could you give me the way.
here is the "duplicate" code I want to rewrite :
func getIntegerValue (listValues: [Any], numValueToRead: Int, readValue: inout Int) -> Bool {
if numValueToRead < 0 || numValueToRead >= listValues.count {
return false
}
let value = listValues [numValueToRead]
if type (of: value) == type(of: readValue) {
readValue = value as! Int
return true
} else {
return false
}
}
func getStringValue (listValues: [Any], numValueToRead: Int, readValue: inout String) -> Bool {
if numValueToRead < 0 || numValueToRead >= listValues.count {
return false
}
let value = listValues [numValueToRead]
if type (of: value) == type(of: readValue) {
readValue = value as! String
return true
} else {
return false
}
}
Here is the code I wrote but do not compile :
func getValue <T> (listValues: [Any], numValueToRead: Int, readValue: inout T) -> Bool {
if numValueToRead < 0 || numValueToRead >= listValues.count {
return false
}
let value = listValues [numValueToRead]
if type (of: value) == type(of: readValue) {
switch value {
case let integerValue as Int:
readValue = integerValue
case let stringValue as String:
readValue = stringValue
default:
return false
}
return true
} else {
return false
}
}
for those affectations I got those compilation errors :
readValue = integerValue -> 'Int' is not convertible to 'T'
readValue = stringValue -> 'String' is not convertible to 'T'
Is there a way to synthetise my two functions with a unique one using generics ?
You theoretically could make it compile by adding forced casts, since you already know that value has the type T:
case let integerValue as Int:
readValue = integerValue as! T
case let stringValue as String:
readValue = stringValue as! T
But the far better solution is to use a conditional cast (as? T) and
conditional binding (if let):
func getValue<T>(listValues: [Any], numValueToRead: Int, readValue: inout T) -> Bool {
if numValueToRead < 0 || numValueToRead >= listValues.count {
return false
}
let value = listValues[numValueToRead]
if let tvalue = value as? T {
readValue = tvalue
return true
} else {
return false
}
}
which then works for arbitrary types, not only Int and String.
A “swiftier” way would be return an optional value (with nil
indicating "no value"). The code can then be simplified to
func getValue<T>(listValues: [Any], numValueToRead: Int) -> T? {
guard listValues.indices.contains(numValueToRead) else {
return nil
}
return listValues[numValueToRead] as? T
}
This should work:
func getValue <T> (listValues: [Any], numValueToRead: Int, readValue: inout T) -> Bool {
if numValueToRead < 0 || numValueToRead >= listValues.count {
return false
}
let value = listValues [numValueToRead]
if type (of: value) == type(of: readValue) {
if let genericValue = value as? T {
readValue = genericValue
return true
}
return false
} else {
return false
}
}
At first sight, the function is wrongly named. You cannot call function getValue when it returns bool... I would call it transform or modify or something other than get value, because you are NOT getting value.
I think this method suits better your needs, not tested tought it should work.
func transformValue<T>(from listValues: [Any], numValueToRead: Int, readValue: inout T?) throws -> Bool {
// Guard suits better this case...
guard numValueToRead > 0 || numValueToRead < listValues.count else { return false }
let value = listValues[numValueToRead]
if type (of: value) == type(of: readValue) {
guard let value = value as? T else {
throw NSError(
domain: "Smth",
code: 1,
userInfo: ["Description": "Failed to cast to generic type T"]
)
}
readValue = value as? T
return true
}
return false // No need to call else...
}
Explenation: Returning optional generic type T is much safer. You try to cast it, you fail and you throw error that something went wrong. In my opinion saving force casts with throwing errors is much more safer approach, you know what went wrong and so.
As #MartinR pointed out, returning a nil value instead of an inout+Bool combination gives the same results, but with less, and more readable code. This is the path Swift also took when importing most of the NSError ** methods from Objective-C (i.e. dropped the last parameter, imported them as throwable functions).
These being said, another approach would be to add an extension over Array for extracting the value:
extension Array {
subscript<T>(_ index: Int, as type: T.Type) -> T? {
guard 0..<count ~= index else { return nil }
return self[index] as? T
}
}
let arr: [Any] = [1, "two", 3, "four"]
arr[1, as: String.self] // two
arr[2, as: String.self] // nil

overloading methods where only difference is optional vs. non-optional type

I was under the impression that swift can have overloaded methods that differ only in the type of object that the methods return. I would think that I could have two funcs with the same signature yet they differ in return type.
import Foundation
// ambiguous use of 'IsTextEmpty(text:)'
func IsTextEmpty(text : String?) -> Bool? {
return text?.isEmpty
}
func IsTextEmpty(text : String?) -> Bool {
guard let text = text else {
return true
}
return text.isEmpty
}
let text: String? = nil
if let empty = IsTextEmpty(text:"text") {
print("Not Empty")
}
if IsTextEmpty(text: text) {
print("Empty")
}
Here, both functions have the same input parameters but one func returns an optional Bool? and the other returns a Bool. In this case I get an error:
ambiguous use of 'IsTextEmpty(text:)'
If I change the name of one of the input parameters I no longer get the ambiguous error:
// Works
func IsTextEmpty(foo : String?) -> Bool? {
return foo?.isEmpty
}
func IsTextEmpty(text : String?) -> Bool {
guard let text = text else {
return true
}
return text.isEmpty
}
let text: String? = nil
if let empty = IsTextEmpty(foo:"text") {
print("Not Empty")
}
if IsTextEmpty(text: text) {
print("Empty")
}
Shouldn't the compiler detect that they are two distinct methods even though their return types are different, since an optional Bool? is a different type from a non-optional Bool?
The compiler needs some context to decide which method to call, e.g.
let e1 = IsTextEmpty(text: text) as Bool
let e2: Bool = IsTextEmpty(text: text)
to call the non-optional variant, or
let e3 = IsTextEmpty(text: text) as Bool?
let e4: Bool? = IsTextEmpty(text: text)
to call the optional variant. Now
if IsTextEmpty(text: text) {
print("Empty")
}
compiles without problems: the if-statement requires a boolean
expression, so there is no ambiguity here.
But apparently the compiler is not smart enough to figure out that
in the context of an optional binding the expression on the right-hand side must be some optional
and to infer the unwrapped type automatically.
You need to annotate the type of empty explicitly:
if let empty: Bool = IsTextEmpty(text: text) { ... }
or to make the return type explicit:
if let empty = (IsTextEmpty(text: text) as Bool?) { ... }

Expression pattern of type 'String' cannot match values of type 'AVMetadataKey'

I'm trying to convert my Swift 3 code to Swift 4. I get this error message:
Expression pattern of type 'String' cannot match values of type 'AVMetadataKey'
private extension JukeboxItem.Meta {
mutating func process(metaItem item: AVMetadataItem) {
switch item.commonKey
{
case "title"? :
title = item.value as? String
case "albumName"? :
album = item.value as? String
case "artist"? :
artist = item.value as? String
case "artwork"? :
processArtwork(fromMetadataItem : item)
default :
break
}
}
Please ⌘-click on commonKey and you will see that the argument is of type AVMetadataKey rather than String.
You are encouraged to read the documentation. It's worth it and you can fix yourself an issue like this in seconds.
I added a guard statement to exit the method immediately if commonKey is nil.
private extension JukeboxItem.Meta {
func process(metaItem item: AVMetadataItem) {
guard let commonKey = item.commonKey else { return }
switch commonKey
{
case .commonKeyTitle :
title = item.value as? String
case .commonKeyAlbumName :
album = item.value as? String
case .commonKeyArtist :
artist = item.value as? String
case .commonKeyArtwork :
processArtwork(fromMetadataItem : item)
default :
break
}
}
}

How do I tell which guard statement failed?

If I’ve got a bunch of chained guard let statements, how can I diagnose which condition failed, short of breaking apart my guard let into multiple statements?
Given this example:
guard let keypath = dictionary["field"] as? String,
let rule = dictionary["rule"] as? String,
let comparator = FormFieldDisplayRuleComparator(rawValue: rule),
let value = dictionary["value"]
else
{
return nil
}
How can I tell which of the 4 let statements was the one that failed and invoked the else block?
The simplest thing I can think of is to break out the statements into 4 sequential guard else statements, but that feels wrong.
guard let keypath = dictionary["field"] as? String
else
{
print("Keypath failed to load.")
self.init()
return nil
}
guard let rule = dictionary["rule"] as? String else
{
print("Rule failed to load.")
self.init()
return nil
}
guard let comparator = FormFieldDisplayRuleComparator(rawValue: rule) else
{
print("Comparator failed to load for rawValue: \(rule)")
self.init()
return nil
}
guard let value = dictionary["value"] else
{
print("Value failed to load.")
self.init()
return nil
}
If I wanted to keep them all in one guard statement, I can think of another option. Checking for nils inside the guard statement might work:
guard let keypath = dictionary["field"] as? String,
let rule = dictionary["rule"] as? String,
let comparator = FormFieldDisplayRuleComparator(rawValue: rule),
let value = dictionary["value"]
else
{
if let keypath = keypath {} else {
print("Keypath failed to load.")
}
// ... Repeat for each let...
return nil
}
I don't even know if that will compile, but then I might as well have used a bunch of if let statements or guards to begin with.
What's the idiomatic Swift way?
Erica Sadun just wrote a good blog post on this exact topic.
Her solution was to hi-jack the where clause and use it to keep track of which guard statements pass. Each successful guard condition using the diagnose method will print the file name and the line number to the console. The guard condition following the last diagnose print statement is the one that failed. The solution looked like this:
func diagnose(file: String = #file, line: Int = #line) -> Bool {
print("Testing \(file):\(line)")
return true
}
// ...
let dictionary: [String : AnyObject] = [
"one" : "one"
"two" : "two"
"three" : 3
]
guard
// This line will print the file and line number
let one = dictionary["one"] as? String where diagnose(),
// This line will print the file and line number
let two = dictionary["two"] as? String where diagnose(),
// This line will NOT be printed. So it is the one that failed.
let three = dictionary["three"] as? String where diagnose()
else {
// ...
}
Erica's write-up on this topic can be found here
Normally, a guard statement doesn't let you distinguish which of its conditions wasn't satisfied. Its purpose is that when the program executes past the guard statement, you know all the variables are non-nil. But it doesn't provide any values inside the guard/else body (you just know that the conditions weren't all satisfied).
That said, if all you want to do is print something when one of the steps returns nil, you could make use of the coalescing operator ?? to perform an extra action.
Make a generic function that prints a message and returns nil:
/// Prints a message and returns `nil`. Use this with `??`, e.g.:
///
/// guard let x = optionalValue ?? printAndFail("missing x") else {
/// // ...
/// }
func printAndFail<T>(message: String) -> T? {
print(message)
return nil
}
Then use this function as a "fallback" for each case. Since the ?? operator employs short-circuit evaluation, the right-hand side won't be executed unless the left-hand side has already returned nil.
guard
let keypath = dictionary["field"] as? String ?? printAndFail("missing keypath"),
let rule = dictionary["rule"] as? String ?? printAndFail("missing rule"),
let comparator = FormFieldDisplayRuleComparator(rawValue: rule) ?? printAndFail("missing comparator"),
let value = dictionary["value"] ?? printAndFail("missing value")
else
{
// ...
return
}
Very good question
I wish I had a good answer for that but I have not.
Let's begin
However let's take a look at the problem together. This is a simplified version of your function
func foo(dictionary:[String:AnyObject]) -> AnyObject? {
guard let
a = dictionary["a"] as? String,
b = dictionary[a] as? String,
c = dictionary[b] else {
return nil // I want to know more ☹️ !!
}
return c
}
Inside the else we don't know what did go wrong
First of all inside the else block we do NOT have access to the constants defined in the guard statement. This because the compiler doesn't know which one of the clauses did fail. So it does assume the worst case scenario where the first clause did fail.
Conclusion: we cannot write a "simple" check inside the else statement to understand what did not work.
Writing a complex check inside the else
Of course we could replicate inside the else the logic we put insito the guard statement to find out the clause which did fail but this boilerplate code is very ugly and not easy to maintain.
Beyond nil: throwing errors
So yes, we need to split the guard statement. However if we want a more detailed information about what did go wrong our foo function should no longer return a nil value to signal an error, it should throw an error instead.
So
enum AppError: ErrorType {
case MissingValueForKey(String)
}
func foo(dictionary:[String:AnyObject]) throws -> AnyObject {
guard let a = dictionary["a"] as? String else { throw AppError.MissingValueForKey("a") }
guard let b = dictionary[a] as? String else { throw AppError.MissingValueForKey(a) }
guard let c = dictionary[b] else { throw AppError.MissingValueForKey(b) }
return c
}
I am curious about what the community thinks about this.
One possible (non-idiomatic) workaround: make use of the where clause to track the success of each subsequent optional binding in the guard block
I see nothing wrong with splitting up your guard statements in separate guard blocks, in case you're interested in which guard statement that fails.
Out of a technical perspective, however, one alternative to separate guard blocks is to make use of a where clause (to each optional binding) to increment a counter each time an optional binding is successful. In case a binding fails, the value of the counter can be used to track for which binding this was. E.g.:
func foo(a: Int?, _ b: Int?) {
var i: Int = 1
guard let a = a where (i+=1) is (),
let b = b where (i+=1) is () else {
print("Failed at condition #\(i)")
return
}
}
foo(nil,1) // Failed at condition #1
foo(1,nil) // Failed at condition #2
Above we make use of the fact that the result of an assignment is the empty tuple (), whereas the side effect is the assignment to the lhs of the expression.
If you'd like to avoid introducing the mutable counter i prior the scope of guard clause, you could place the counter and the incrementing of it as a static class member, e.g.
class Foo {
static var i: Int = 1
static func reset() -> Bool { i = 1; return true }
static func success() -> Bool { i += 1; return true }
}
func foo(a: Int?, _ b: Int?) {
guard Foo.reset(),
let a = a where Foo.success(),
let b = b where Foo.success() else {
print("Failed at condition #\(Foo.i)")
return
}
}
foo(nil,1) // Failed at condition #1
foo(1,nil) // Failed at condition #2
Possibly a more natural approach is to propagate the value of the counter by letting the function throw an error:
class Foo { /* as above */ }
enum Bar: ErrorType {
case Baz(Int)
}
func foo(a: Int?, _ b: Int?) throws {
guard Foo.reset(),
let a = a where Foo.success(),
let b = b where Foo.success() else {
throw Bar.Baz(Foo.i)
}
// ...
}
do {
try foo(nil,1) // Baz error: failed at condition #1
// try foo(1,nil) // Baz error: failed at condition #2
} catch Bar.Baz(let num) {
print("Baz error: failed at condition #\(num)")
}
I should probably point out, however, that the above is probably closer to be categorized as a "hacky" construct, rather than an idiomatic one.
The simplest thing I can think of is to break out the statements into 4 sequential guard else statements, but that feels wrong.
In my personal opinion, the Swift way shouldn't require you to check whether the values are nil or not.
However, you could extend Optional to suit your needs:
extension Optional
{
public func testingForNil<T>(#noescape f: (Void -> T)) -> Optional
{
if self == nil
{
f()
}
return self
}
}
Allowing for:
guard let keypath = (dictionary["field"] as? String).testingForNil({ /* or else */ }),
let rule = (dictionary["rule"] as? String).testingForNil({ /* or else */ }),
let comparator = FormFieldDisplayRuleComparator(rawValue: rule).testingForNil({ /* or else */ }),
let value = dictionary["value"].testingForNil({ /* or else */ })
else
{
return nil
}
My two cents:
Since Swift doesn't let me add the where in the guard let, I came up with this solution instead:
func validate<T>(_ input: T?, file: String = #file, line: Int = #line) -> T? {
guard let input = input else {
print("Nil argument at \(file), line: \(line)")
return nil
}
return input
}
class Model {
let id: Int
let name: String
init?(id: Int?, name: String?) {
guard let id = validate(id),
let name = validate(name) else {
return nil
}
self.id = id
self.name = name
}
}
let t = Model(id: 0, name: "ok") // Not nil
let t2 = Model(id: 0, name: nil) // Nil
let t3 = Model(id: nil, name: "ok") // Nil
I think other answers here are better, but another approach is to define functions like this:
func checkAll<T1, T2, T3>(clauses: (T1?, T2?, T3?)) -> (T1, T2, T3)? {
guard let one = clauses.0 else {
print("1st clause is nil")
return nil
}
guard let two = clauses.1 else {
print("2nd clause is nil")
return nil
}
guard let three = clauses.2 else {
print("3rd clause is nil")
return nil
}
return (one, two, three)
}
And then use it like this
let a: Int? = 0
let b: Int? = nil
let c: Int? = 3
guard let (d, e, f) = checkAll((a, b, c)) else {
fatalError()
}
print("a: \(d)")
print("b: \(e)")
print("c: \(f)")
You could extend it to print the file & line number of the guard statement like other answers.
On the plus side, there isn't too much clutter at the call site, and you only get output for the failing cases. But since it uses tuples and you can't write a function that operates on arbitrary tuples, you would have to define a similar method for one parameter, two parameters etc up to some arity. It also breaks the visual relation between the clause and the variable it's being bound to, especially if the unwrapped clauses are long.
This code can be used for all guard and if logic tests like optional, bool and case tests. It prints a line of a logic test which failed.
class GuardLogger {
var lastGoodLine: Int
var lineWithError: Int { lastGoodLine + 1 }
var file: String
var function: String
init(file: String = #file, function: String = #function, line: Int = #line) {
self.lastGoodLine = line
self.file = file
self.function = function
}
func log(line: Int = #line) -> Bool {
lastGoodLine = line
return true
}
func print() {
Swift.print([file, function, String(lineWithError)].joined(separator: " "))
}
}
let testBoolTrue = true
let testBoolFalse = false
let guardLogger = GuardLogger()
guard
testBoolTrue, guardLogger.log(),
let testOptionalBoolTrue = Optional(testBoolTrue), guardLogger.log(),
let selfIsViewController = self as? UIViewController, guardLogger.log(),
testBoolTrue == false, guardLogger.log() // this fails
else {
print(guardLogger.lastGoodLine)
fatalError()
}