6

この質問CKRecordは、Swift で添え字を使用できるかどうかを尋ねます。質問者が望んでいたことを行う方法はすでに知っていましたが、それを順列するたびにスタックオーバーフローが発生します。

subscript(key: String) -> CKRecordValue? {
    get {
        return objectForKey(key) as CKRecordValue?
    }
    set {
        setObject(newValue, forKey: key)
    }
}

ゲッターでスタックオーバーフローが発生します。(セッターは試したことがないのでそちらでも発生するかもしれません。) objectForKey:objectForKeyedSubscript:、 で実装してみましvalueForKey:た。すべてが同じ結果を生成します: スタック オーバーフロー。

CKRecord確かにObjective-Cで書かれているので、これは非常に奇妙です。Swift のsubscriptメソッドを再帰的に呼び出すのはなぜですか? 意味がない。Nate Cook は、質問者への回答の中で、なぜ Swift が自動的にブリッジしないのか疑問に思っていobjectForKeyedSubscript:ます。それを行うためのコードが完全に焼き付けられていない可能性がありますが、この問題を引き起こしています。を持つ別のクラスで試してみる必要がありobjectForKeyedSubscript:ます。

アップデート

objectForKeyedSubscript:通常はブリッジされているようです。適切なメソッドを使用して Objective-C でクラスを作成し、それをブリッジング ヘッダーに追加すると、インデクサーがそこにあり、問題なくコンパイルされました。さらに良いことに、スタックオーバーフローなしで機能しました。

これは、 で非常に異常なことが起こっていることを意味しCKRecordます。

理論

Swift で、 aをキーとしてメソッドを継承しNSObjectて実装するクラスを作成すると、 this になります。(「純粋な Swift」クラスの場合、これは当てはまらないと思います。) これは、Swift クラスを Objective-C にインポートし、そこにあることを確認することで確認できます。subscriptStringobjectForKeyedSubscript:objectForKeyedSubscript:

からCKRecord派生しているためNSObject、実装subscriptするとデフォルトの実装がオーバーライドされます。さらに、objectForKey:and valueForKey:all 最終的に呼び出された のように見えますがobjectForKeyedSubscript:、その結果 (読み取り: "is the same as") が呼び出されsubscript、スタック オーバーフローが発生します。

これが、スタック オーバーフローが発生する理由を説明している可能性があります。が自動的にブリッジされなかった理由はまだ説明されていませんobjectForKeyedSubscript:が、おそらく、 の定義がsetObject:forKeyedSubscript:正規のものとはわずかに異なる型シグネチャを持っているためです- (void)setObject:(id <CKRecordValue>)object forKeyedSubscript:(NSString *)key;。これは Objective-C と何の違いもありませんが、「ブリッジング コード」につまずく可能性があります。結局のところ、Swift はかなり新しいものです。

4

3 に答える 3

2

(サブクラスを介して) いくつかのテストとデバッグを行った後、 for が実際に を呼び出すことを発見しCKRecordましobjectForKey:objectForKeyedSubscript:。また、暗黙的に (からの派生によって)subscriptマークされている Swift クラスで実装することは、 として実装されていることを明示的に意味します。@objcNSObjectsubscriptobjectForKeyedSubscript:

これは、拡張機能subscriptで onを実装すると、デフォルトの実装が隠され、スタック オーバーフローが発生することを意味します。CKRecord

于 2014-11-27T00:09:16.830 に答える
1

これは、添え字を付けやすくするための CKRecord の簡単な拡張です。

extension CKRecord {
    struct Sub {
        let record: CKRecord

        subscript(key: String) -> CKRecordValue? {
            get {
                return record.objectForKey(key) as? CKRecordValue
            }
            set {
                record.setObject(newValue, forKey: key)
            }
        }
    }

    var sub: Sub {
        return Sub(record: self)
    }

    var : Sub {
        return sub
    }
}

使用法:

var sub = record.sub
sub["name"] = name

/* Or */

// One does not simply subscript CKRecord
record.["name"] = name

(ちなみに冗談です)

于 2015-05-20T08:35:06.500 に答える
1

Apple のエンジニアが開発者フォーラムで書いたコードに便乗することで、うまく添え字を付けることができました。

import CloudKit

protocol MyCKRecordValueType {
    var asObject: CKRecordValue { get }
}

extension CKRecord {
    func set<ValueType>(value: ValueType, forKey key: String) where ValueType : MyCKRecordValueType {
        let object = value.asObject
        self.setObject(object, forKey: key)
    }
    subscript(key : String) -> MyCKRecordValueType? {
        set {
            self.setObject(newValue?.asObject, forKey: key)
        }
        get {
            return object(forKey: key) as? MyCKRecordValueType
        }
    }
}

extension String : MyCKRecordValueType {
    var asObject: CKRecordValue { return self as NSString }
}
extension Bool : MyCKRecordValueType {
    var asObject: CKRecordValue { return self as NSNumber }
}
extension Int : MyCKRecordValueType {
    var asObject: CKRecordValue { return self as NSNumber }
}
extension Data : MyCKRecordValueType {
    var asObject: CKRecordValue { return self as NSData }
}

その後、期待どおりに添え字を呼び出すことができます。

let firstRecordID = CKRecordID(recordName: "0")

        let record = CKRecord(recordType: "Foo", recordID: firstRecordID)

        record["title"] = "Hello World"

        record["year_established"] = 2000
于 2017-10-11T00:12:21.050 に答える