4

What's the most convenient code to write

[results valueForKey:@"attribute"]

in swift? I've found here that it's recommended to use the map() function with a closure:

swiftarray.map({$0["attribute"]})

N.B. swiftarray is not a NSArray

Community
  • 1
  • 1
aneuryzm
  • 63,052
  • 100
  • 273
  • 488
  • For some reason my computer has decided it no longer wants to run any Swift code (useful...) but I'm pretty sure you can run this and just remove the parentheses from it? I think possibly both ways are valid though. Have you tried this in a playground? TBH, I can't see how the error you are getting is related to the code you have posted? Is it definitely from it? – Fogmeister Mar 24 '16 at 16:19
  • Could you post the entire use case? What type is your array? – Sulthan Mar 24 '16 at 16:27
  • 2
    @Fogmeister "my computer has decided it no longer wants to run any Swift code" Wow, I think I'd like to hear more about _that_! – matt Mar 24 '16 at 16:32
  • @matt no idea how it happened or how to fix it :( I suspect it would involve reinstalling OSX. But yeah, playgrounds just sit there with the spinner but not executing any code and projects don't compile. Can't remember the error though. – Fogmeister Mar 24 '16 at 17:05

3 Answers3

9

I'am not sure but if you have some object in array other than Dictionary (or other type that supports subscripting), you will need to use following code

results.map({$0.attribute})
Peter K
  • 438
  • 3
  • 10
  • I actually get the error message: "AnyObject" has no member "attribute-name" – aneuryzm Mar 30 '16 at 08:20
  • Then you need to cast you AnyObject to the real object type that contains in your results array – Peter K Mar 30 '16 at 08:41
  • Which means I cannot use the concise closure you wrote in your answer, because I need to specify the type of the parameter in the signature of the closure. – aneuryzm Mar 30 '16 at 09:17
  • 1
    You can cast you results array to array of your actual object type before this mapping and the use this closure. Something like that `if let actualResult = result as? [MyClass] { actualResult.map {$0.attribute} }` – Peter K Mar 30 '16 at 09:28
  • Or less safe `(result as! [MyClass]).map {$0.attribute}` – Peter K Mar 30 '16 at 09:30
  • Can anyone tell me how to do this in swift 4.2 – Mashhadi Dec 17 '18 at 10:24
0

What's the most convenient code to write

[results valueForKey:@"attribute"]

in swift?

That would be:

  results.valueForKey("attribute")
Community
  • 1
  • 1
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 1
    For an array of custom objects, I get the error `Value of type '[TestObject]' has no member 'valueForKey'` – James Webster Mar 24 '16 at 16:36
  • 1
    @JamesWebster Obviously the object to which you send `valueForKey` would need to be a class derived from NSObject, because that's where `valueForKey` lives. If you've got an array, it needs to be an NSArray, and its elements need to be NSObject derivatives. But that is not what the OP asked (as far as I can tell)... Or is it? – matt Mar 24 '16 at 16:46
  • 2
    @Matt Why do you assume that the array is a derived from NSObject? This is a swift array, not a NSArray. I also get the message has no member 'valueForKey'. Otherwise the question would be a really stupid one. – aneuryzm Mar 24 '16 at 19:48
  • @Biclops No, but the OP asked the wrong question. I answered the wrong-headed question that the OP asked. After all, if Objective-C `valueForKey:` works on a particular NSArray of a particular kind of object, Swift `value(forKey:)` will work perfectly well on an NSArray of that same kind of object. – matt Apr 04 '17 at 01:39
0

Does your class have a subscript?

I've been able to create a test class which can use the KVC accessors like so:

class TestObject
{
    var name:String
    var numbers:[String:Int] = [String:Int]()

    init(name:String)
    {
        self.name = name
    }

    subscript(index: String) -> Int? {
        get {
            return numbers[index]
        }
        set(newValue) {
            numbers[index] = newValue
        }
    }
}

Tested with the following code:

let testObject1 = TestObject(name: "test1")
testObject1["home-phone"] = 1234
testObject1["mobile-phone"] = 5678

let testObject2 = TestObject(name: "test2")
testObject2["office"] = 0987
testObject2["mobile-phone"] = 6543

let array : [TestObject] = [testObject1, testObject2]

var results = array.map({$0["office"]})
print("Results:\(results)")

results = array.map({$0["mobile-phone"]})
print("Results:\(results)")

produces the following result:

Results:[nil, Optional(987)]
Results:[Optional(5678), Optional(6543)]
James Webster
  • 31,873
  • 11
  • 70
  • 114