Skip to content

Commit e65ae80

Browse files
authored
Merge pull request #36955 from mininny/add-dynamic-subclass-kvo-doc
2 parents 67176e7 + dd5e2aa commit e65ae80

File tree

4 files changed

+21
-3
lines changed

4 files changed

+21
-3
lines changed

include/swift/ABI/Metadata.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,8 +1168,25 @@ struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
11681168
Description = description;
11691169
}
11701170

1171+
// [NOTE: Dynamic-subclass-KVO]
1172+
//
1173+
// Using Objective-C runtime, KVO can modify object behavior without needing
1174+
// to modify the object's code. This is done by dynamically creating an
1175+
// artificial subclass of the the object's type.
1176+
//
1177+
// The isa pointer of the observed object is swapped out to point to
1178+
// the artificial subclass, which has the following properties:
1179+
// - Setters for observed keys are overridden to additionally post
1180+
// notifications.
1181+
// - The `-class` method is overridden to return the original class type
1182+
// instead of the artificial subclass type.
1183+
//
1184+
// For more details, see:
1185+
// https://www.mikeash.com/pyblog/friday-qa-2009-01-23.html
1186+
11711187
/// Is this class an artificial subclass, such as one dynamically
11721188
/// created for various dynamic purposes like KVO?
1189+
/// See [NOTE: Dynamic-subclass-KVO]
11731190
bool isArtificialSubclass() const {
11741191
assert(isTypeMetadata());
11751192
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

0 commit comments

Comments
 (0)