[SR-3935] Initializing from @objc protocol with Protocol.Type causes a memory leak #46520
Labels
bug
A deviation from expected or documented behavior. Also: expected but undesirable behavior.
compiler
The Swift compiler in itself
memory leak
bug: Memory leak
Environment
Version:
Xcode 8.2.1, macOS Sierra 10.12.3
reproducible on simulator and on device iOS 10.2
Additional Detail from JIRA
md5: 66af2db86394c6844503ec9fb73ac839
is duplicated by:
Issue Description:
Summary:
When initializing an object from protocol.Type with required init the object is leaked even after everything related was released.
Scenario:
I have a protocol named "Plugin"
the protocol has required init with Int param `public required init(param: Int)`
I also have a function:
`func create(plugin: Plugin.Type) -> Plugin`
when I create a plugin using createPlugin(param: ) the instance is initialized and working, but when I look at the memory graph and in instruments I see that the objects created by createPlugin are leaked and has +1 reference count by some unknown factor.
To summarize, an object initialized by protocol.Type gets leaked and an object initialized by a common super class or a non @objc protocol gets initialized just fine.
Steps to reproduce the issue:
1. create the following classes and protocols:
@objc protocol Plugin {
init()
}
@objc class TestPlugin: NSObject, Plugin {
required override init() { }
}
2. in a view controller put the following:
instance property: `var pluginType: Plugin.Type?`
in viewDidLoad or any other view controller life cycle method put this:
`pluginType = TestPlugin.self`
`let plugin = pluginType!.init()`
run the sample project with this declarations and you will see a leaked object right away.
if you will remove the @objc from the protocol you will see there is no issue. something about the bridging between swift -> objc doesn't work here for protocols.
Expected Results:
An Initialized object that work and doesn't have a memory leak
Actual Results:
An initialized object that works BUT has a memory leak
A temporary fix is creating an AbstractPlugin class and receive this class instance.Type instead of the protocols.
Like this:
`class AbstractPlugin: Plugin`
`func create(plugin: AbstractPlugin.Type) -> AbstractPlugin`
OR
creating another protocol to be with @objc for example:
`@objc protocol Plugin`
`protocol MyPlugin: Plugin`
this way I can receive Plugin object and before initializing cast it to MyPlugin which isn't @objc and this way it is created without a leak.
Notes:
The issue only exists for @objc protocols and classes, if the app/framework is for swift only then there is no issue.
To fix this issue on places we must have swift and objc together we need to create a common base class and use BaseClass.Type instead of protocol. this way the object is initialized without a leak.
There is a bug report I opened with this number: 30478887
The text was updated successfully, but these errors were encountered: