https://baked-corn.tistory.com/30
https://velog.io/@msi753/ARC
์ฐธ์กฐํ๋ ๋ณ์๋ฅผ ์นด์ดํธํ๋ ์์คํ
์์๋ ๋ณ์๊ฐ weakํ์
์ ๊ธฐ๋ณธ์ผ๋ก ์ฌ์ฉํ๋ ์ด์ ๋
strong๊ณผ weak๋ ์ด๋ป๊ฒ ๋ค๋ฅธ๊ฐ์? ๐
ํ ์์ด๊ฐ ํ์ ์ ๋ค๊ณ ์๋ ์ํฉ์ ๊ฐ์ ํด๋ณด์.
์์ด๊ฐ ํ์ ์ ๋ค๊ณ ์๋ ๊ฒ์ด strong,
ํ์ ๊ณผ ์์ด์ ์ฐ๊ฒฐ๊ด๊ณ๊ฐ weak์ด๋ค.
๊ธฐ๋ณธ์ ์ธ ํด๋์ค(reference type)๋ ๊ฐํ ์ฐธ์กฐ์ด๋ค.
๋ถ๋ชจ ๊ฐ์ฒด๊ฐ ์์ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๋ฉด ์นด์ดํธ๊ฐ 1์ด ์ฆ๊ฐํ๊ณ , ์์ ๊ฐ์ฒด๊ฐ ๋ถ๋ชจ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๋ฉด ์นด์ดํธ๊ฐ 1์ด ์ฆ๊ฐํ๋ค.
์ํ์ฐธ์กฐ๋ฅผ ํ๊ธฐ ๋๋ฌธ์ ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ๋ฐ์ํ ์ ๋ฐ์ ์๋ค.
class TestClass{
var testClass: TestClass? = nil
init(){
print("init")
}
deinit(){
print("deinit")
}
}
var testClass1: TestClass? = TestClass()
var testClass2: TestClass? = TestClass()
testClass1?.testClass = testClass2
testClass2?.testClass = testClass1
testClass1 = nil
testClass2 = nil
>> init
>> init
deinitํ์ง ์์
๋ฉ๋ชจ๋ฆฌ ํด์ ๋ถ๊ฐ๋ฅ(๋ฉ๋ชจ๋ฆฌ ๋์)
๋ถ๋ชจ๊ฐ ์์์ ๊ฐํ๊ฒ ์ฐธ์กฐํ๋ฉด ์นด์ดํธ๊ฐ 1 ์ฆ๊ฐํ์ง๋ง, ์์์ ๋ถ๋ชจ๋ฅผ ์ฝํ๊ฒ ์ฐธ์กฐํ๊ณ ์๊ธฐ ๋๋ฌธ์ ์นด์ดํธ๊ฐ ์ฆ๊ฐํ์ง ์๋๋ค
class TestClass{
weak var testClass: TestClass? = nil // ์ด์ ์ด ์ฐธ์กฐ๋ ์ฝํ ์ฐธ์กฐ์ด๋ค!
init(){
print("init")
}
deinit(){
print("deinit")
}
}
var testClass1: TestClass? = TestClass()
var testClass2: TestClass? = TestClass()
testClass1?.testClass = testClass2
testClass2?.testClass = testClass1
testClass1 = nil
testClass2 = nil
>> init
>> init
>> deinit
>> deinit
๊ฐ์ฒด์ ๋ฉ๋ชจ๋ฆฌ๊ฐ ํด์ ๋ ํ ๊ทธ์ ๋์ํ๋ ๋ณ์๋ ์๋์ผ๋ก nil์ด ๋ ๊ฒ์
๋๋ค.
optional ํ์
๋ง์ด nil๊ฐ์ด ๋ ์ ์๊ธฐ ๋๋ฌธ์ ๋ชจ๋ weak ์ฐธ์กฐ ๋ณ์๋ ๋ฐ๋์ optional ํ์
์ด์ด์ผ ํฉ๋๋ค.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let alert = UIAlertController(title: "Title", message: "Message", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Done", style: .cancel, handler: { [weak self] _ in
self?.doSomething()
}))
present(alert, animated: true)
}
private func doSomething() {
print("doSomething")
}
}
๋ฃจํ ๋ฐ์(์ํ์ฐธ์กฐ ์ค๋ฅ)๋ก ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ๋ฐ์ํ๋ค
ํด๋ก์ ์์ self๋ฅผ ์ฌ์ฉํ๋ฉด scope's life ๋์ self๋ฅผ strong referenceํ๊ฒ๋ฉ๋๋ค.
ViewController์์ UIAlertController๋ฅผ ์ฌ๋ฆฌ๊ณ ( ๊ฐํ์ฐธ์กฐ: ViewController -> UIAlertController),
UIAlertController๊ฐ ์๋ฃ๋๋ฉด self.doSomething์ ์คํ์ํค๋๋ฐ self๋ ViewController๋ฅผ ๊ฐ๋ฆฌํจ๋ค ( ๊ฐํ์ฐธ์กฐ: UIAlertController -> ViewController)
[weak self]๋ก ์ํ ์ฐธ์กฐ ๋ฃจํ๋ฅผ ์์ค๋ค
(UIAlertController -> ViewController)๋ฅผ ์ต์
๋๋ก ์ฝํ ์ฐธ์กฐ๋ก ๋ง๋ค์ด ๋ฃจํ๋ฅผ ์ ๊ฑฐํ๋ค
[weak self] _ in // [weak self]
self?.doSomething() // ์ต์
๋๋ก ๋ณ๊ฒฝ
ํด๋ก์ ์์ [weak self]๋ฅผ ์ฌ์ฉํ ๋,
self๋ฅผ ์ต์
๋๋ก ๋ง๋ค๊ธฐ ๋๋ฌธ์, ์์ฒ๋ผ self?.data = data์ฒ๋ผ ์ธ ์๋ ์์ง๋ง,
guard let
์ ์ฌ์ฉํด ์ผ์์ ์ผ๋ก ํด๋ก์ ์ ์์์ self๋ฅผ strong referenceํด์ค ์๋ ์๋ค.
private var data: Data?
private func getData(string: String, completion: ((Data?)->Void)) {
completion(nil)
}
func foo() {
getData(string: "") { [weak self] data in
guard let strongSelf = self else {
return
}
strongSelf.data = data
// ์๋๋ฉด self?.data = data๋ก ์ผ์ ๊ฑฐ๋ค
}
}
protocol SomeDelegate: AnyObject {
func didTapThing()
}
//Foo๊ฐ ํ์ ์ ๋ค๊ณ ์๋ ์ด๋ฆฐ์์ด
//ViewController๊ฐ ํ์
class Foo: SomeDelegate {
init() {
let vc = ViewController() // Foo->ViewController ๊ฐํ์ฐธ์กฐ
vc.delegate = self // ViewController->Foo ๊ฐํ์ฐธ์กฐ
}
public func didTapThing() {
//
}
}
class ViewController: UIViewController {
weak var delegate: SomeDelegate?
}
unowned๋ก ์ ์ธ๋ ๋ณ์๋ ์ ๋ nil์ด ๋ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ฏ๋ก unowned ๋ณ์๋ optional๋ก ์ ์ธ๋์ด์๋ ์ ๋ ์๋ฉ๋๋ค. ๋ง์น unwrappingํ๋ ๊ฒ๊ณผ ๊ฐ์ต๋๋ค. unowned๋ ํด์ ๋ ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ์ ๊ทผํ์ง ์๋๋ค๋ ํ์คํ ๊ฒฝ์ฐ๋ง ์ฌ์ฉํด์ผํ๋ค๋ ๋ป์
๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์ฑ์ด crashํฉ๋๋ค.
ํด๋น ๋ณ์๊ฐ ๊ฐ๋ฆฌํค๋ ๊ฐ์ฒด์ ๋ฉ๋ชจ๋ฆฌ๊ฐ ํด์ ๋ ์ดํ์๋ ํด๋น ์์ญ์ ๊ฐ๋ฆฌํค์ง ์๋๋ค๋ ํ์ ์ด ์๋ค๋ฉด ๋น์ ์ unowned๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
let changeColorToRed = DispatchWorkItem { [unowned self] in
guard let self = self else { return }
self.view.backgroundColor = .red
}
์์ ๋ทฐ ์ปจํธ๋กค๋ฌ๋ฅผ ๊ฐ๊ณ ์๋ ๋ถ๋ชจ ๋ทฐ ์ปจํธ๋กค๋ฌ
๋ถ๋ชจ ๋ทฐ ์ปจํธ๋กค๋ฌ๊ฐ pop๋์ ๋ ๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฐฉ์ง
class ParentViewController: UIViewController, ChildViewControllerProtocol: class{
let childViewController = ChildViewController()
func prepareChildViewController(){
childViewController.delegate = self
}
}
protocol ChildViewControllerProtocol {
// important functions
}
class ChildViewController: UIViewController {
//var delegate: ChildViewControllerProtocol? ์ฌ๊ธฐ!
weak var delegate: ChildViewControllerProtocol?
}
UITableView์์์ ์์
weak public var dataSource: UITableViewDataSource?
weak public var delegate: UITableViewDelegate?
TestClass ๊ฐ์ฒด์ ๋ด๋ถ์์ Closure๋ก, Closure์์ TestClass๊ฐ์ฒด๋ก ๊ฐํ ์ฐธ์กฐ
-> weak self๋ฅผ captureํด์ค์ผ๋ก์จ ํด๊ฒฐ
class TestClass{
var aBlock: (()->())? = nil
let aConstant = 5
init(){
print("init")
aBlock = { [weakself] in // ์ฌ๊ธฐ!
//aBlock = {
print(self.aConstant)
}
}
deinit(){
print("deinit")
}
}
var testClass: TestClass? = TestClass()
testClass = nil
closure ๋ธ๋ก์ locallyํ๊ฒ ์ฌ์ฉํ๋ค๋ฉด self๋ฅผ weakํ๊ฒ captureํ ํ์๊ฐ ์์
-> ์์ UIView.animateWithDuration
class TestClass {
let aConstant = 5
init() {
print("init")
let aBlock = {
print(self.aConstant)
}
}
deinit {
print("deinit")
}
}
var testClass: TestClass? = TestClass()
testClass = nil
class TestClass{
let aConstant = 5
init(){
print("init")
}
deinit(){
print("deinit")
}
func doSomething(){
UIView.animate(withDuration: 5){
let aConstant = self.aConstant
// fancy animation ... .
}
}
}
var testClass: TestClass? = TestClass()
testClass?.doSomething()
testClass = nil
๋ชจ๋ View Controller๋ง๋ค ์ด๋ฌํ ๋ฉ์๋๋ฅผ ์์ฑํด์ฃผ๋ ๊ฒ์ด ์ข์ต๋๋ค
let timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true, block: { [unowned self] (timer: Timer) in
if self.progressSlider.isTracking { return }
self.progressSlider.value = Float(self.player.currentTime)
})
ํ๋ก์ ํธ MusicPlayer๋ฅผ ๋ง๋ค๋ฉด์ unowned self๋ฅผ ์ดํดํ์ง ๋ชปํด์ ๊ฒ์ํ๋ค.
๋ฉ๋ชจ๋ฆฌ๋ฅผ ์๋์ผ๋ก ๊ด๋ฆฌํด์ฃผ๋ ARC์ ์ฐ๊ด๋ ๋ถ๋ถ์ด๋ฉฐ, ์ฝํ ์ฐธ์กฐ๋ฅผ ์๋ฏธํ๋ค.
weak์ unowned๊ฐ ๋ค๋ฅธ ์ ์ optional, nil์ด ๋ ์ ์๊ณ , ํด์ ํ ๋ฐ๋์ ํด๋น ์์ญ์ ๊ฐ๋ฆฌํค๋ ์ผ์ด ์์ด์ผ ํ๋ค๋ ๊ฒ์ด๋ค.
์ ์ญ์ ์ผ๋ก ์ฌ์ฉํ๋ Timer, ํด๋์ค์ ๋ง์ฐฌ๊ฐ์ง๋ก ๊ฐํ ์ฐธ์กฐ๋ฅผ ํ๋ ํด๋ก์ ์ ์ฑ์ง ๋๋ฌธ์,
ํด๋ก์ ๋ธ๋ก์ weakํ๊ฒ captureํ ๊ฒ์ด๋ค.