2017-03-02 6 views
3

Swift配列とNSArraysの間でキャストするのは簡単です。私はコンパイルする必要はないと思うケースが見つかりました:`var objCArray = array as NSArray`は法的にはなぜですか?

let doubleArray = [1.1, 2.22, 3.333, 4.4444, 5.55555, 
    6.666666, 7.7777777, 8.88888888, 9.999999999] 

var objCArray = doubleArray as NSArray 

二行目はダブルスの私スウィフト配列からNSArrayのが作成されますが、それはvarに格納します。これは、コンパイラが配列の内容を変更することが合理的であることをテストします。それはobjCArrayがvarとして宣言されていても、あなたはその配列を変異しようとした場合、あなたがエラーを取得することを意味します

objCArray[0] = 123 

なぜラインvar objCArray = doubleArray as NSArrayは合法ですか?

+2

'var objCArray'は、後で別のものを割り当てることができるという意味です。 'var objCArray = someOtherDoubleArray as NSArray' –

+4

なぜそれが違法であるべきですか? 'var objCArray'は可変ポインタを定義します。可変ポインタは、そのポインタが保持しているアドレスを変更することができます。それが指しているオブジェクトが可変であるかどうかは別の問題です –

答えて

0

NSArrayは不変オブジェクトです。 と呼ばれるサブクラスNSArrayがあり、それに含まれるオブジェクトを変更することができます。コードをvar objCArray = doubleArray as NSMutableArrayに変更すると、求めていることを行うことができます。

+0

これはなぜ "var objCArray = doubleArray as NSArray'が有効なのですか? – JAL

+0

@ JAL "なぜ合法的なのですか"という直接的な質問には答えませんが、 "objCArray [0] = 2'と言うと、どうしてエラーになるのですか? – creeperspeak

+0

技術的には、NSArrayの 'subscript'は' get'だけです。私の答えを見てください。 – JAL

2

これは有効です。varは、後でMartinにコメントのように何かを割り当てることができるという意味です。 NSArrayは不変オブジェクトです。 NSArray財団スウィフトモジュールでは、subscriptは唯一getとしてマークされています

extension NSArray { 

    // ... 

    @available(iOS 6.0, *) 
    open subscript(idx: Int) -> Any { get } 

    // ... 
} 

ブリッジ法的である理由については、スウィフトアレイモジュールでこのノートを参照してください。

/// Bridging Between Array and NSArray 
/// ================================== 
/// 
/// When you need to access APIs that expect data in an `NSArray` instance 
/// instead of `Array`, use the type-cast operator (`as`) to bridge your 
/// instance. For bridging to be possible, the `Element` type of your array 
/// must be a class, an `@objc` protocol (a protocol imported from Objective-C 
/// or marked with the `@objc` attribute), or a type that bridges to a 
/// Foundation type. 
/// 
/// The following example shows how you can bridge an `Array` instance to 
/// `NSArray` to use the `write(to:atomically:)` method. In this example, the 
/// `colors` array can be bridged to `NSArray` because its `String` elements 
/// bridge to `NSString`. The compiler prevents bridging the `moreColors` 
/// array, on the other hand, because its `Element` type is 
/// `Optional<String>`, which does *not* bridge to a Foundation type. 
/// 
///  let colors = ["periwinkle", "rose", "moss"] 
///  let moreColors: [String?] = ["ochre", "pine"] 
/// 
///  let url = NSURL(fileURLWithPath: "names.plist") 
///  (colors as NSArray).write(to: url, atomically: true) 
///  // true 
/// 
///  (moreColors as NSArray).write(to: url, atomically: true) 
///  // error: cannot convert value of type '[String?]' to type 'NSArray' 
/// 
/// Bridging from `Array` to `NSArray` takes O(1) time and O(1) space if the 
/// array's elements are already instances of a class or an `@objc` protocol; 
/// otherwise, it takes O(*n*) time and space. 
/// 
/// Bridging from `NSArray` to `Array` first calls the `copy(with:)` 
/// (`- copyWithZone:` in Objective-C) method on the array to get an immutable 
/// copy and then performs additional Swift bookkeeping work that takes O(1) 
/// time. For instances of `NSArray` that are already immutable, `copy(with:)` 
/// usually returns the same array in O(1) time; otherwise, the copying 
/// performance is unspecified. The instances of `NSArray` and `Array` share 
/// storage using the same copy-on-write optimization that is used when two 
/// instances of `Array` share storage. 
/// 
/// - Note: The `ContiguousArray` and `ArraySlice` types are not bridged; 
/// instances of those types always have a contiguous block of memory as 
/// their storage. 
/// - SeeAlso: `ContiguousArray`, `ArraySlice`, `Sequence`, `Collection`, 
/// `RangeReplaceableCollection` 
5
let doubleArray = [1.1, 2.22, 3.333, 4.4444, 5.55555, 6.666666, 7.7777777, 8.88888888, 9.999999999] 
var objCArray = doubleArray as NSArray 

なぜvar var objCArray = doubleArrayがNSArrayとして有効なのですか

他のすべてのvar宣言と同様に、変数の値を置き換えることができるためです。この場合は、あなたが異なるにNSArrayとobjCArrayでNSArrayのを置き換えるために許可されます:

objCArray = [2.9] 

をそれにもかかわらず、NSArrayの自体は不変です。これは、このObjective-Cクラスに関する単なる事実です。たとえば、objCArray[0]に割り当てることはできません。これは対varとは関係ありません。それはNSArrayの自体が何であるかについての事実です:

objCArray[0] = 123 // error 

を今、あなたは言うかもしれない:それはスウィフト構造体の仕組みとは全く違うのです。本当です!しかし、NSArrayはではなく、 Swift構造体です。スウィフトではなく、構造体ではありません。これはObjective-Cクラスです! Swift ArrayはSwift構造体なので、代わりに使用する必要があります。


さらなる議論:それはスタンドとして質問は、あきらか馬鹿げている、と私たちも、もっぱらスウィフトの構造体に集中することで、これを見ることができます:あなたがに割り当てる許可されている

  • var Swiftの構造体のプロパティ構造体参照自体がvarで宣言されている場合。

  • あなたは、構造体の参照自体はvarで宣言されている場合でもスウィフト、における構造体のletプロパティに割り当てることが許されないです。

  • しかし、structにはletのプロパティしかないため、varと宣言することはできません。それは不条理です。しかし、その馬鹿げさはあなたの質問の不合理とまったく同じです。

    struct S { 
        let name = "Matt" 
    } 
    var s = S() // should this be illegal... 
    // ... just because assigning to S.name is illegal??? 
    
+0

その行を 'var objCArray = doubleArray'に変更したらどうなりますか? 'objCArray'を突然変異させることができるのでしょうか、または初期の不変配列の値を変更しようとしているので、実行時エラーが出ますか? – halileohalilei

+0

@halileohalileiそれを試してみてください。 (そして、あなたが行うときに推論された型の 'objCArray'を見てください。) – matt

+0

誰かが不思議に思っていたら、私はそれを試して、2番目の配列はこの場合の最初の**コピー**です。第2のものの推論された型も第1の配列と同じです。 – halileohalilei

0

スウィフト不変配列(doubleArray)が自動(フリーダイヤル)ブリッジを介してNSArrayのと互換性があるため、型キャストが合法です。したがって、objCArrayへの代入によって、元の値を持つ型(不変)への変更可能な参照が得られます。

その後、objCArrayは参照型として扱われます。

これは、オブジェクトタイプ(NSArray)が許可する任意のメソッドを実行して、変数(objCArray)に新しいオブジェクトインスタンスを割り当てることができることを意味します。

この場合、NSArrayクラスは不変の配列を操作するように設計されているため、値を添字に割り当てることはできません。コンパイラは、NSArrayオブジェクトを参照する変数の変更可能性に基づいてではなく、NSArrayのサブスクリプトの実装に基づいてこれを検出します。

参照型(NSArray)と値付き型(Swift配列)の違いの1つで、意図したとおりに動作します。 Swiftの "let"は、値付きの型に適用されると、変数の内容が変更されないようにします。参照される型に "let"を使用すると、参照変数を変更できなくなりますが、参照されるオブジェクトの内容を変更することができます。

関連する問題