Objective-Cクラス
OCに精通している人は、上の図に精通している必要があります。はい、これはAppleの公式インスタンスオブジェクト、クラス、およびメタクラスの関係図です。isa、スーパークラス、およびメタクラスの関係を鮮明に示しています。継承関係
OCクラスの実装原理を見れば、OCクラスはobjc_classから継承され、NSObjectはOCのタイプであり、objc_objectはcのタイプであることがわかります。
構造タイプobjc_classはobjc_objectタイプを継承します。ここで、objc_objectも構造であり、isa属性を持っているため、objc_classもisa属性を持っています。
NSObjectのisaは、下部のClassによって定義され、クラスの下部のコードはobjc_class型から取得されるため、NSObjectにもisa属性があります。
NSObjectはクラスです。これを使用してインスタンスオブジェクトobjcを初期化します。objcはobjc_objectの特性を満たします(つまり、isa属性を持ちます)。これは主に、isaがNSObjectによってobjc_classから継承され、objc_classがobjc_objectから継承され、objc_objectがisaを持っているためです。属性。 したがって、オブジェクトにはisaがあります。これは、現在のobjc_objectを指していることを意味します。
objc_objectは現在のルートオブジェクトであり、すべてのオブジェクトにはそのような特性objc_objectがあります。つまり、isa属性があります。
OCクラスの分析と調査については、以前のブログを参照してください 。 クラスクラスの基本原則に関するiOSの詳細な分析 。
では、Swiftのクラスも同じですか? Swiftのクラスの構造は何ですか? その基礎となる実装はどうですか?
クラス構造
1.構造
前回のブログでは、Swiftのインスタンスオブジェクトを分析しました。インスタンスオブジェクトの場合、その本質は、デフォルトのメモリサイズが16バイトのHeapObject構造です(メタデータ8バイト+ refCounts 8バイトの2つの属性があります)。
Swiftオブジェクト分析については、私のブログを参照してください 。 オブジェクトの基本原理に関するSwiftの詳細な分析 。
HeapObjectのメモリ割り当てを理解すると、メタデータに気付くはずです。そのタイプはHeapMetadataです。その特定のメモリ構造を見てみましょう。
2、HeapMetadataタイプ分析
TargetHeapMetaDataタイプのエイリアスであるHeapMetadata定義を入力し、パラメーターInprocessを受け取ります。
struct InProcess;
template < typename Target> struct TargetHeapMetadata;
using HeapMetadata = TargetHeapMetadata< InProcess> ;
#else
typedef struct HeapMetadata HeapMetadata;
typedef struct HeapObject HeapObject;
#endif
TargetHeapMetaData定義を入力します。これは、基本的にテンプレートタイプであり、いくつかの必要なデータ構造を定義します。 この構造には属性はなく、初期化メソッドのみが渡され、MetadataKindタイプのパラメーターが渡されます。kindは渡されたインプロセスです。
template < typename Runtime>
struct TargetHeapMetadata : TargetMetadata< Runtime> {
using HeaderType = TargetHeapMetadataHeader< Runtime> ;
TargetHeapMetadata ( ) = default ;
constexpr TargetHeapMetadata ( MetadataKind kind)
: TargetMetadata< Runtime> ( kind) {
}
#if SWIFT_OBJC_INTEROP
constexpr TargetHeapMetadata ( TargetAnyClassMetadata< Runtime> * isa)
: TargetMetadata< Runtime> ( isa) {
}
#endif
} ;
using HeapMetadata = TargetHeapMetadata< InProcess> ;
constexpr TargetHeapMetadata(MetadataKind kind)は初期化メソッドであり、種類のタイプは次のとおりです。
名前
値
クラス
0x0
構造体
0x200
列挙型
0x201
オプション
0x202
ForeignClass
0x203
不透明
0x300
タプル
0x301
関数
0x302
実存的
0x303
メタタイプ
0x304
ObjCClassWrapper
0x305
ExistentialMetatype
0x306
HeapLocalVariable
0x400
HeapGenericLocalVariable
0x500
ErrorObject
0x501
LastEnumerated
0x7FF
TargetMetaData定義を入力します。kind属性があり、kindのタイプは以前に渡されたインプロセスです。 このことから、種類の場合、そのタイプはunsigned longであり、主にどのタイプのメタデータを区別するために使用されると結論付けることができます。
struct TargetMetaData{
using StoredPointer = typename Runtime: StoredPointer;
. . .
StoredPointer kind;
}
struct Inprocess{
. . .
using StoredPointer = uintptr_t;
. . .
}
typedef unsigned long uintptr_t;
TargetHeapMetadataとTargetMetaDataの定義から、初期化メソッドのパラメーターの種類のタイプはMetadataKindであることがわかります。
MetadataKind定義を入力します。#include "MetadataKind.def"があり、クリックして入力します。これは、すべてのタイプのメタデータを記録します。
TargetMetaData構造体定義に戻り、メソッドgetClassObjectを見つけます。このメソッドで種類を一致させると、戻り値はTargetClassMetadataタイプになります。Classの場合は、これ(現在のポインター、つまりメタデータ)をClassMetadataに直接強制します。
const TargetClassMetadata< Runtime> * getClassObject ( ) const ;
template< > inline const ClassMetadata *
Metadata: : getClassObject ( ) const {
switch ( getKind ( ) ) {
case MetadataKind: : Class: {
return static_cast< const ClassMetadata * > ( this) ;
}
case MetadataKind: : ObjCClassWrapper: {
auto wrapper = static_cast< const ObjCClassWrapperMetadata * > ( this) ;
return wrapper-> Class;
}
default :
return nullptr;
}
}
したがって、TargetMetadataとTargetClassMetadataは基本的に同じです。これは、メモリ構造ではポインタを直接変換できるため、構造は実際にはTargetClassMetadataであると見なすことができるためです。
TargetAnyClassMetadataから継承されたTargetClassMetadata定義を入力すると、クラス構造の一部である次の属性があります。
template < typename Runtime>
struct TargetClassMetadata : public TargetAnyClassMetadata< Runtime> {
. . .
ClassFlags Flags;
uint32_t InstanceSize;
uint16_t InstanceAlignMask;
uint16_t Reserved;
uint32_t ClassSize;
uint32_t ClassAddressPoint;
. . .
}
TargetHeapMetadataから継承されたTargetAnyClassMetadata定義を入力します。
template < typename Runtime>
struct TargetAnyClassMetadata : public TargetHeapMetadata< Runtime> {
. . .
ConstTargetMetadataPointer< Runtime, swift: : TargetClassMetadata> Superclass;
TargetPointer< Runtime, void > CacheData[ 2 ] ;
StoredSize Data;
. . .
}
総括する
1.Swiftクラスの構成
メタデータの種類がクラスの場合、次の継承チェーンがあります。
現在のクラスによって返される実際の型はTargetClassMetadataであり、TargetMetaDataには属性の種類が1つだけあり、TargetAnyClassMetaDataにはkind、superclass、cacheData、dataの4つの属性があります。
メモリに格納されている現在のクラスの属性は、TargetClassMetadata属性+ TargetAnyClassMetaData属性+ TargetMetaData属性で構成されているため、結果のメタデータ構造は次のようになります。
struct swift_class_t: NSObject{
void * kind;
void * superClass;
void * cacheData;
void * data;
uint32_t flags;
uint32_t instanceAddressOffset;
uint32_t instanceSize;
uint16_t instanceAlignMask;
uint16_t reserved;
uint32_t classSize;
uint32_t classAddressOffset;
void * description;
. . .
}
2.SwiftクラスとOCクラスの比較
OCのインスタンスオブジェクトは基本的に構造であり、基になるobjc_objectを介して作成され、クラスはobjc_classから継承されます。Swiftのインスタンスオブジェクトも本質的に構造であり、タイプはHeapObjectであり、OCよりもrefCountが1つ多くなります。 ;
OCのメソッドはobjc_class構造class_rw_tのmethodListに格納され、swiftのメソッドはメタデータに格納されます。
OCのARCはハッシュテーブルを維持します。SwiftのARCには、オブジェクト内にrefCountsプロパティがあります。