Retain is an object lifecycle helper that provides a simple way to control object retaining and observing it
To run the example project, clone the repo, and run pod install
from the Example directory first.
- Swift 5.5 or higher
- iOS 13.0 or higher
- MacOS 10.15 or higher
- TVOS 13.0 or higher
- WatchOS 8.0 or higher
- XCode 13 or higher
Retain is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod 'Retain', '~> 1.0.2'
- Add it using XCode menu File > Swift Package > Add Package Dependency
- Add https://github.com/hainayanda/Retain.git as Swift Package URL
- Set rules at version, with Up to Next Major option and put 1.0.2 as its version
- Click next and wait
Add as your target dependency in Package.swift
dependencies: [
.package(url: "https://github.com/hainayanda/Retain.git", .upToNextMajor(from: "1.0.2"))
]
Use it in your target as a Retain
.target(
name: "MyModule",
dependencies: ["Retain"]
)
hainayanda, [email protected]
Retain is available under the MIT license. See the LICENSE file for more info.
You can observe object deallocation very easily by using the global function whenDeallocate(for:do:)
:
let cancellable = whenDeallocate(for: myObject) {
print("myObject is deallocated")
}
It will produce Combine's AnyCancellable
and the closure will be called whenever the object is being deallocated by ARC
.
If you prefer to get the underlying publisher instead, use deallocatePublisher(of:)
:
let myObjectDeallocationPublisher: AnyPublisher<Void, Never> = deallocatePublisher(of: myObject)
there's one protocol named DeallocateObservable
that can expose the global function as a method so it can be used directly from the object itself:
class MyObject: DeallocateObservable {
...
...
}
so then you can do this to the object:
// get the publisher
let myObjectDeallocationPublisher: AnyPublisher<Void, Never> = myObject.deallocatePublisher
// listen to the deallocation
let cancellable = myObject.whenDeallocate {
print("myObject is deallocated")
}
There's a propertyWrapper
that enables DeallocateObservable
behavior without implementing one named WeakSubject
:
@WeakSubject var myObject: MyObject?
this propertyWrapper
will store the object in a weak variable and can be observed like DeallocateObservable
by accessing its projectedValue
:
// get the publisher
let deallocationPublisher: AnyPublisher<Void, Never> = $myObject.deallocatePublisher
// listen to the deallocation
let cancellable = $myObject.whenDeallocate {
print("current value in myObject propertyWrapper is deallocated")
}
It will always emit an event for as many objects assigned to this propertyWrapper
as long the object is deallocated when still in this propertyWrapper
.
RetainableSubject
is very similar to WeakSubject
. The only difference is, we can control whether this propertyWrapper
will retain the object strongly or weak:
@RetainableSubject var myObject: MyObject?
to change the state of the propertyWrapper
retain state, just access the projectedValue
:
// make weak
$myObject.state = .weak
$myObject.makeWeak()
// make strong
$myObject.state = .strong
$myObject.makeStrong()
Since RetainableSubject
is DeallocateObservable
too, you can do something similar with WeakSubject
:
// get the publisher
let deallocationPublisher: AnyPublisher<Void, Never> = $myObject.deallocatePublisher
// listen to the deallocation
let cancellable = $myObject.whenDeallocate {
print("current value in myObject propertyWrapper is deallocated")
}
You know how, just clone and do a pull request