Edited at

同じインスタンスなのかどうか判定したい時(Swift)


はじめに

前に同じインスタンスかどうかを判定したい時にやり方がわからなかったのでメモ

公式ドキュメントからそのまま引用するが下記のように確かめることができる。


example

class IntegerRef {

let value: Int
init(_ value: Int) {
self.value = value
}
}

let x = IntegerRef(10)
let y = x

print(ObjectIdentifier(x) == ObjectIdentifier(y))
// Prints "true"
print(x === y)
// Prints "true"

let z = IntegerRef(10)
print(ObjectIdentifier(x) == ObjectIdentifier(z))
// Prints "false"
print(x === z)
// Prints "false"


ちなみにObjectIdentifierとは公式ドキュメントによると

A unique identifier for a class instance or metatype.

つまり

クラスインスタンスまたはメタタイプの一意の識別子。

とのこと

識別子という意味がよくわからなかったので下記のコードで調べてみた


試したコード

print("ObjectIdentifier(x)",ObjectIdentifier(x))

print("ObjectIdentifier(y)",ObjectIdentifier(y))
print("ObjectIdentifier(z)",ObjectIdentifier(z))


出力結果

ObjectIdentifier(x) ObjectIdentifier(0x00006000002ca520)

ObjectIdentifier(y) ObjectIdentifier(0x00006000002ca520)
ObjectIdentifier(z) ObjectIdentifier(0x00006000002c1040)

このように同じインスタンスに対しては同じ値が入っていることがわかる


Overviewについて

ドキュメントでは下記のように記述されている

In Swift, only class instances and metatypes have unique identities. 

There is no notion of identity for structs, enums, functions, or tuples.

Swiftでは、クラスインスタンスとメタタイプのみが一意のIDを持ちます。

構造体、列挙型、関数、またはタプルに同一性の概念はありません。

たとえば構造体を下記のように作ってみると

struct IntegerRef2 {

let value: Int
init(_ value: Int) {
self.value = value
}
}

let X = IntegerRef2(10)
print("ObjectIdentifier(X)",ObjectIdentifier(X))

下記のようなエラーが出力される

Cannot invoke initializer for type 'ObjectIdentifier' with an argument list of type '(IntegerRef2)'

ドキュメントのイニシャライザをみてみると

init(AnyObject)

Creates an instance that uniquely identifies the given class instance.

init(Any.Type)
Creates an instance that uniquely identifies the given metatype.

となっており引数はAnyObjectといえど

特定のクラスインスタンスを一意に識別するインスタンスを作成する



与えられたメタタイプを一意に識別するインスタンスを作成する

イニシャライザしかなく、構造体を入れることはできないんだなぁと改めて思った


使い方

一意なクラスの識別子を使ってどんなことができるのかという例

参考にしたライブラリだと下記の例を見つけた

let id = UInt(bitPattern: ObjectIdentifier({クラスのインスタンスを入れる}))

UInt(bitPattern:)の使い方は下記のように引数にIntを入れたらいいらしい

ドキュメントによるとこの引数は,新しいインスタンスのバイナリ表現のソースとして使用する値をいれてくださいとのこと

init(bitPattern x: Int)

Appleのドキュメントの例だと下記のような感じで続きを書くと

let id1 = UInt(bitPattern: ObjectIdentifier(x))

let id2 = UInt(bitPattern: ObjectIdentifier(y))
let id3 = UInt(bitPattern: ObjectIdentifier(z))
print(id1)
print(id2)
print(id3)

出力結果はこんなかんじ

105553146139456

105553146139456
105553146092352

しかし、入れている値ObjectIdentifier(x)の型はObjectIdentifierなのにどうしてIntの引数にはいるのかはよくわからなかった・・・(わかる方教えてください :bow:)

こういうふうにクラスを引数に入れるとそのクラスが一意になる番号を取得する方法があるのだなと学びになった

//////////////1/6(追記)

昨日気が付かなかったのだけど


init(bitPattern x: Int)


これ以外にちゃんと objectIDでイニシャライズする関数が存在していた

あるやんけ

/// Creates an integer that captures the full value of the given object

/// identifier.
public init(bitPattern objectID: ObjectIdentifier)

//////////////


参考資料

Apple docment init(_:)

Apple docment init(bitPattern:)