I recently encountered an issue where my method swizzling for NSData and NSString stopped working after updating to iOS 18. The tests I wrote for swizzling Data and String using extensions on NSData and NSString worked fine on iOS 16 and iOS 17, but they fail on iOS 18. After experimenting, I realized the issue only occurs on iOS 18.
The swizzling approach worked perfectly on earlier iOS versions but seems to be blocked or ignored in iOS 18. I’m wondering if there have been changes to the Swift or Objective-C runtime in iOS 18 that prevent method swizzling for NSData, NSString, or their Swift counterparts like Data and String. Has anyone else faced this issue, and are there any known workarounds?
Does this mean method swizzling is no longer possible in iOS 18 for these types, or is there something else I should look into? 😔
What I’ve tried:
in the extension:
extension NSString {
@objc static func swizzle() {
let originalSelector1 = #selector(write(to:atomically:encoding:))
let swizzledSelector1 = #selector(swizzled_write(to:atomically:encoding:))
SwizzleHelper.swizzle(for: self, from: originalSelector1, to: swizzledSelector1)
let originalSelector2 = #selector(write(toFile:atomically:encoding:))
let swizzledSelector2 = #selector(swizzled_write(toFile:atomically:encoding:))
SwizzleHelper.swizzle(for: self, from: originalSelector2, to: swizzledSelector2)
}
}
from SwizzleHelper:
@objc static func swizzle(for clazz: AnyClass?,
from originalSelector: Selector,
to swizzledSelector: Selector)
{
guard let originalMethod = class_getInstanceMethod(clazz, originalSelector),
let swizzledMethod = class_getInstanceMethod(clazz, swizzledSelector)
else {
return
}
method_exchangeImplementations(originalMethod, swizzledMethod)
}
and testing:
func testWritingDataToFileWithNSStringStringPath() {
let fileManager = FileManager.default
let docDir = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
.appendingPathComponent("SomeFiles").appendingPathComponent("SwizzlingTest")
try! fileManager.createDirectory(at: docDir, withIntermediateDirectories: true)
NSString.swizzle()
let filePath = docDir.appendingPathComponent("sample.log")
do {
try sampleText.write(toFile: filePath.path, atomically: true, encoding: .utf8)
} catch {
XCTAssertNotNil(error)
}
XCTAssertFalse(fileManager.fileExists(atPath: filePath.path), "File still created :( : (filePath.path)")
}
Verified the issue only occurs on iOS 18; swizzling works fine on iOS 17, iOS 16, etc.
Explicitly casting String to NSString and Data to NSData, but still no luck on iOS 18.
Any insights would be appreciated!
4