Cannot invoke 'filter' with an argument list of type '((_) -> _)' - swift

Sounds ridiculous, but I'm unable to fix this piece of code:
self.runningScripts.filter({ $0 != scriptRunner })
No matter how I write the closure I always get this error:
Cannot invoke 'filter' with an argument list of type '((_) -> _)'
runningScripts is defined like this:
var runningScripts = [ScriptRunner]()
and ScriptRunner is a Swift class (does not inherit from NSObject)
I'm using nearly the same in many other places without problems. Any suggestions?

You can get that error if you didn't make ScriptRunner conform to Equatable:
class ScriptRunner : Equatable {
// the rest of your implementation here
}
func ==(lhs: ScriptRunner, rhs: ScriptRunner) -> Bool {
return ... // change this to whatever test that satisfies that lhs and rhs are equal
}

I needed an explicit cast like this:
#NSManaged private var storage: [String]
private var objects: Set<String>?
func remove(element:String) {
initSetIfNeeded()
if(objects!.contains(element)) {
objects!.remove(element)
storage = storage.filter({($0 as NSObject) !== (element as NSObject)}) // Explicit cast here!!
}
}

Related

swift generics: append not found for array

My first attempt to use swift generics:
extension RealmSwift.List where Element == Object {
// #deprecated use RealmSwift.List<>
func arrayo<T: Object>() -> [T] {
var res: [T] = []
for card in self {
res.append(card) <- here I got
No exact matches in call to instance method 'append'
}
return res
}
convenience init<T: Object>(objects: [T]) {
self.init()
for card in objects {
append(card)
}
}
}
what's a good way to write this adapter once and for all?
Notice the where Element. You can refer to the type of the list items using Element, so you do not need to set up another type parameter T. card is of type Element not T, so you cannot add it to the Array<T>. There is no guarantee that T and Element are equivalent so the compiler doesn't allow it. The same applies for your convenience init.
extension RealmSwift.List where Element == Object {
// #deprecated use RealmSwift.List<>
func arrayo() -> [Element] {
var res: [Element] = []
for card in self {
res.append(card) // Now you are adding an `Element` to the array of `Element` so it will work.
}
return res
}
convenience init(objects: [Element]) {
self.init()
for card in objects {
append(card)
}
}
}
But generics are not really useful here because you are constraining Element to Object already. So there is only one potential type - You could make arrayo() and the init use Object directly.
To make this useful do
extension RealmSwift.List where Elemtn: RealmCollectionValue

Can not check equality of values of type T: Equatable inside a generic

I'm currently trying out with some basic data structures like LinkedList. I defined a ListNode class of generics values, like this:
class ListNode<T> {
var nodeContent: T
var nextNode: ListNode<T>? = nil
init() {
// details omitted here
}
And then a linked list. I want to implement the contains() method, so I have sth like this:
func contains<T>(_ item: T) -> Bool {
var currNode = self.head
while (currNode != nil) {
if currNode?.nodeContent == item {
return true
}
currNode = currNode?.nextNode
}
return false
}
Then it's giving me error saying that '==' cannot applied to T and T types. I then looked through the language guide and changed ListNode class and LinkedList struct to this:
class ListNode<T: Equatable>{}
struct LinkedList<T: Equatable>{}
But it's not working, so I added 'Equatable' to func itself:
func contains<T: Equatable>(_ item: T) -> Bool
Still fails. I tried pasting the sample function from the language guide inside,
func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
for (index, value) in array.enumerated() {
if value == valueToFind {
return index
}
}
return nil
}
No error occurs. May I know why it's like this? I tried searching, but all suggested answers like this doesn't clear my doubts. Thanks in advance!
You just don't need to make the contains method generic (twice). It's inside of your already generic class and knows about T type. It's right to require T: Equatable in the type declaration.
findIndex(of:in:) works as is, because it's not a method, but rather a standalone generic function.

How to call a static method on a base class from a generic class<T>?

I'm trying to call a static method in a base class from a generic subclass. See simplified playground code below.
Calling the non-static 'dump' function works.
The similar static call fails. Various attempts to typecast the array also fail.
In the full production code, "ClassA" is in a 3rd-party module and can't be changed. It can be further subclassed and extended.
Does Swift offer some magical typecast to have ClassT call ClassA.dump() directly?
class ClassT<T> {
var dict=[String:T]()
func add(key:String, obj:T) {
dict[key]=obj
let arr=Array(dict.values)
dump(arr) // works -> but not as expected, see comment below !!!
ClassA.dump(arr) // error: cannot convert value of type 'Array<T>' to expected argument type '[ClassA]'
ClassA.dump(arr as! [ClassA]) // error: cannot convert value of type 'Array<T>' to type '[ClassA]' in coercion
ClassA.dump(arr as! [AnyObject]) // error: 'AnyObject' is not a subtype of 'T'
ClassA.dump(arr as! [Any]) // error: 'Any' is not a subtype of 'T'
}
}
class ClassA {
func dump(arr:[ClassA]) {
ClassA.dump(arr)
}
static func dump(arr:[ClassA]) {
print(arr)
}
}
class ClassB:ClassA {
static let o=ClassT<ClassA>()
func test() {
ClassB.o.add("Elem1", obj:self)
}
}
You have to add a constraint to specify that T derives from ClassA.
class ClassT<T: ClassA> {
var dict = [String : T]()
func add(key: String, obj: T) {
dict[key] = obj
let arr = Array(dict.values) //probably unecessary
dump(arr) // works
ClassA.dump(arr)
}
//...
Without it, the compiler has no way to enforce that all conforming types T will be castable to ClassA.

Swift dynamicType does not work with generic function

Say I have a protocol:
protocol VehicleModel {...}
It is implemented by a number of different structs. (e.g. CarModel, TruckModel, etc.)
I have a generic method to get the vehicle's 'model identifier'.
func modelIdentifierForVehicle<V: VehicleModel>(vehicleType: V.Type) -> String {
return "\(vehicleType)"
}
If I call modelIdentifierForVehicle(CarModel.self) this returns "Car" just fine. But if I have a polymorphic collections of VehicleModel's and I try to call modelIdentifierForVehicle(model.dynamicType) on each of them, Xcode says "Cannot invoke 'modelIdentifierForVehicle' with argument list of type (VehicleModel.Type)" Why is this? And how can I work around it?
Since you're only converting vehicleType to a String in modelIdentifierForVehicle, I would argue why you need to use constrain V to VehicleModel, or even use generics at all:
func typeIdentifier(t: Any.Type) -> String {
return "\(t)"
}
let vehicles: [VehicleModel.Type] = [CarModel.self, TruckModel.self]
typeIdentifier(vehicles[0]) // CarModel
If there's a reason you need use a VehicleModel, assuming VehicleModel doesn't use Self or associated type requirements, you could do:
func modelIdentifierForVehicle(vehicleType: VehicleModel.Type) -> String {
return "\(vehicleType)"
}
If you're using Swift 2, you could instead use a protocol extension:
extension VehicleModel {
static var modelIdentifier: String {
return "\(self.dynamicType)"
}
}
// The array from earlier.
vehicles[1].modelIdentifier // TruckModel.Type

Swift generic parameter cannot be bound to non-#objc protocol

The following code produces a compile error of "Generic parameter "T" cannot be bound to non-#objc protocol type 'AAA' on the fail line. When I use a class instead of a protocol, it works ok. Also, if I add an #objc to the protocol it also works, but only in 6.4 beta. Any suggestions would be helpful.
protocol AAA {
var id: String { get set }
}
class BBB: AAA {
var id: String = ""
}
class BBBService {
func getAll<T:AAA>() -> [T] {
var returnArray:[T] = [T]()
return returnArray
}
}
class TestIt
{
func myTest() {
var service = BBBService()
var fail:[AAA] = service.getAll() // fails with Generic parameter "T" cannot be bound to non-#objc protocol type AAA
var succeed:[BBB] = service.getAll()
}
}
this also fails:
<T where T:AAA>
Update - from a practical perspective, adding the #objc causes other problems in my app. So, that is not an option at this point and time.
The trouble is with this line:
getAll<T: AAA>() -> [T]
you are declaring that T must be a concrete type that implements the protocol AAA. It’s important to distinguish between the protocol AAA, i.e. code like this:
func getAll() -> [AAA] {
var returnArray: [AAA] = [BBB()]
return returnArray
}
which works fine (returns an array of references to AAA-conforming objects, which could be of type BBB, or type CCC), and this:
func getAll<T: AAA>() -> [T] {
var returnArray: [T] = [] // what is T? No idea.
return returnArray
}
in which you are saying to the compiler “write me a version of getAll, in which T can be replaced by any specific type that implements AAA”.
This is why your second version compiles - you’re fixing T to be the actual type BBB.
Bear in mind, T might be a struct. In which case the array returned must be sized specifically for whatever struct is being held, right there as a value within the array. As opposed to if the protocol was #objc in which case it would at least be known to only be a class reference of a fixed size.
If what you actually want is an array of protocols, you should remove the generic placeholder and just return an array of protocols:
func getAll() -> [AAA] {
var returnArray: [AAA] = []
return returnArray
}