Skip to content

Commit 3ca4555

Browse files
committed
[docs] Add short note about dynamic subclassing and KVO
1 parent f75f5fe commit 3ca4555

File tree

5 files changed

+26
-5
lines changed

5 files changed

+26
-5
lines changed

include/swift/ABI/Metadata.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,6 +1170,26 @@ struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
11701170

11711171
/// Is this class an artificial subclass, such as one dynamically
11721172
/// created for various dynamic purposes like KVO?
1173+
//
1174+
// [NOTE: Dynamic-subclass-KVO]
1175+
// To implement Key-Value Observing without any code that notifies the
1176+
// observer, the KVO infrastructure uses dynamic subclassing with Objective-C
1177+
// runtime. When a variable is observed, KVO creates a secret dynamic subclass
1178+
// of that class under the hood which are defined with a prefix of
1179+
// `NSKVONotifying_`.
1180+
//
1181+
// While the observed variables have the type of the dynamic subclass, they
1182+
// must appear like their non-observed counterparts for the front-end user. To
1183+
// achieve this, the dynamic subclass overrides `-class` method which returns
1184+
// the original class type, and internally refers to the subclass in the
1185+
// runtime.
1186+
//
1187+
// In the created subclass, `-set` methods for observed variables are
1188+
// overridden, where the calls to the observer notifications are triggered.
1189+
// KVO only generates one dynamic subclass for each class which overrides all
1190+
// setter methods of variables being observed. That is, setters of variables
1191+
// that are not observed are also not overridden in the dynamic subclass for
1192+
// efficiency.
11731193
bool isArtificialSubclass() const {
11741194
assert(isTypeMetadata());
11751195
return Description == nullptr;

include/swift/RemoteAST/RemoteAST.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,11 +184,11 @@ class RemoteASTContext {
184184
/// resolve it to a specific type in the local AST.
185185
///
186186
/// \param skipArtificial If true, the address may be an artificial type
187-
/// wrapper that should be ignored. For example, it could be a
187+
/// wrapper that should be ignored. For example, it could be a
188188
/// dynamic subclass created by (e.g.) CoreData or KVO; if so, and this
189189
/// flag is set, this method will implicitly ignore the subclass
190190
/// and instead attempt to resolve a type for the first non-artificial
191-
/// superclass.
191+
/// superclass. See [NOTE: Dynamic-subclass-KVO].
192192
Result<Type>
193193
getTypeForRemoteTypeMetadata(remote::RemoteAddress address,
194194
bool skipArtificial = false);

include/swift/Runtime/Casting.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ swift_getDynamicType(OpaqueValue *value, const Metadata *self,
224224
/// Fetch the type metadata associated with the formal dynamic
225225
/// type of the given (possibly Objective-C) object. The formal
226226
/// dynamic type ignores dynamic subclasses such as those introduced
227-
/// by KVO.
227+
/// by KVO. See [NOTE: Dynamic-subclass-KVO]
228228
///
229229
/// The object pointer may be a tagged pointer, but cannot be null.
230230
SWIFT_RUNTIME_EXPORT

stdlib/public/runtime/Metadata.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ static GenericMetadataCache &getCache(
385385
}
386386

387387
#if SWIFT_PTRAUTH && SWIFT_OBJC_INTEROP
388+
// See [NOTE: Dynamic-subclass-KVO]
388389
static void swift_objc_classCopyFixupHandler(Class oldClass, Class newClass) {
389390
auto oldClassMetadata = reinterpret_cast<const ClassMetadata *>(oldClass);
390391

stdlib/public/runtime/SwiftObject.mm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ static Class _swift_getObjCClassOfAllocated(const void *object) {
9292
/// Fetch the ObjC class object associated with the formal dynamic
9393
/// type of the given (possibly Objective-C) object. The formal
9494
/// dynamic type ignores dynamic subclasses such as those introduced
95-
/// by KVO.
95+
/// by KVO. See [NOTE: Dynamic-subclass-KVO]
9696
///
9797
/// The object pointer may be a tagged pointer, but cannot be null.
9898
const ClassMetadata *swift::swift_getObjCClassFromObject(HeapObject *object) {
@@ -122,7 +122,7 @@ static Class _swift_getObjCClassOfAllocated(const void *object) {
122122
/// Fetch the type metadata associated with the formal dynamic
123123
/// type of the given (possibly Objective-C) object. The formal
124124
/// dynamic type ignores dynamic subclasses such as those introduced
125-
/// by KVO.
125+
/// by KVO. See [NOTE: Dynamic-subclass-KVO]
126126
///
127127
/// The object pointer may be a tagged pointer, but cannot be null.
128128
const Metadata *swift::swift_getObjectType(HeapObject *object) {

0 commit comments

Comments
 (0)