Runtime is not able to calculate the correct ivar offsets under some specific circumstances. Take a look at the following example:
import Foundation
import Runtime
class IncorrectLayout: NSObject {
let ivar1 = AttributedString("ivar1") // Value type
let ivar2 = NSDate() // Reference type
}
Inspecting this type through Runtime gives the following offsets:
PropertyInfo(name: "ivar1", type: Foundation.AttributedString, isVar: false, offset: 0, ownerType: ...)
PropertyInfo(name: "ivar2", type: NSDate, isVar: false, offset: 8, ownerType: ...)
But that's not correct as far as I understand. According to ivar_getOffset the offsets are off by 8 bytes. Because of that, using get(from:) will return an instance pointing to an invalid memory address, resulting in a crash when invoking any method on it. Eg:
let instance = IncorrectLayout()
let info = try typeInfo(of: IncorrectLayout.self)
try info.properties.forEach { property in
if property.name == "ivar2" {
let ivar = try property.get(from: instance) as NSDate
print(ivar.timeIntervalSinceNow) // Unrecognized selector -[_TtCV10Foundation16AttributedString4Guts timeIntervalSinceNow]!
}
}
Additional notes
Attempting to change almost anything from IncorrectLayout will likely fix the issue. Eg:
- Removing the
NSObject superclass
- Changing the type of ivar1 to a reference type
- Removing ivar1
Runtime is not able to calculate the correct ivar offsets under some specific circumstances. Take a look at the following example:
Inspecting this type through Runtime gives the following offsets:
But that's not correct as far as I understand. According to
ivar_getOffsetthe offsets are off by 8 bytes. Because of that, usingget(from:)will return an instance pointing to an invalid memory address, resulting in a crash when invoking any method on it. Eg:Additional notes
Attempting to change almost anything from
IncorrectLayoutwill likely fix the issue. Eg:NSObjectsuperclass