This question asks if signatures can be used with CKRecord
in Swift. Although I already knew how to do what the request asked, each permutation of it gives me a stack overflow:
subscript(key: String) -> CKRecordValue? { get { return objectForKey(key) as CKRecordValue? } set { setObject(newValue, forKey: key) } }
Stack overflow occurs in the receiver. (I never tried the installer, so this can happen there as well.) I tried to implement using objectForKey:
objectForKeyedSubscript:
and valueForKey:
All produce the same result: stack overflow.
This is very strange, since CKRecord
is certainly written in Objective-C. Why does it call the Swift subscript
method recursively? It makes no sense. Nate Cook in his answer to the questionnaire asks why Swift does not connect objectForKeyedSubscript:
automatically. Well, maybe the code for this is not completely baked, but it causes this problem. I need to try it with another class that has objectForKeyedSubscript:
UPDATE
It looks like objectForKeyedSubscript:
usually connects. I created a class in Objective-C with the appropriate methods, added it to the header of the bridge, and the indexes were there and compiled without problems. Even better, it worked without.
This means that something very unusual is happening with CKRecord
.
THEORY
If you create a class in Swift that descends from NSObject
and implements the subscript
method on it with String
as the key, this becomes objectForKeyedSubscript:
(For pure Swift classes, I suspect this is not the case.) You can verify this by importing your Swift class into Objective-C and checking that objectForKeyedSubscript:
.
Since CKRecord
derived from NSObject
, the subscript
implementation overrides the default implementation. Furthermore, it seems that objectForKey:
and valueForKey:
all ultimately called objectForKeyedSubscript:
which results in a (read: "is same as") call to subscript
, which causes a stack overflow.
This may explain why stack overflow occurs. It still doesn't explain why objectForKeyedSubscript:
not automatically overridden, but perhaps because the definition of setObject:forKeyedSubscript:
has a slightly different type signature from the canonical: - (void)setObject:(id <CKRecordValue>)object forKeyedSubscript:(NSString *)key;
. This does not matter for Objective-C, but can lead to disabling "bridge code". After all, Swift is pretty new.