Swift swizzling init function
From the InputStream
documentation:
NSInputStream
is an abstract superclass of a class cluster consisting of concrete subclasses ofNSStream
that provide standard read-only access to stream data.
The key here: when you create an InputStream
, the object you get back will not be of type InputStream
, but a (private) subclass of InputStream
. Much like the Foundation collection types (NSArray
/NSMutableArray
, NSDictionary
/NSMutableDictionary
, etc.), the parent type you interface with is not the effective type you're working on: when you +alloc
one of these types, the returned object is usually of a private subclass.
In most cases, this is irrelevant implementation detail, but in your case, because you're trying to swizzle an initializer, you do actually care about the value returned from +alloc
, since you're swizzling an initializer which is never getting called.
In the specific case of InputStream
, the value returned from +[NSInputStream alloc]
is of the private NSCFInputStream
class, which is the effective toll-free bridged type shared with CoreFoundation. This is private implementation detail that may change at any time, but you can swizzle the initializer on that class instead:
guard let class = NSClassFromString("NSCFInputStream") else {
// Handle the fact that the class is absent / has changed.
return
}
swizzling(class, #selector(InputStream.init(url:)), #selector(swizzledInit(url:)))
Note that if you're submitting an app for App Store Review, it is possible that the inclusion of a private class name may affect the review process.