์คํ์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉฐ ์ด์๋ฅผ ๋ฐ๊ฒฌํ๊ณ , ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ฌ ์ปจํธ๋ฆฌ๋ทฐํฐ๊น์ง ๋๋ ์ข์ ๊ฒฝํ์ ํ์ฌ ์ ๋ฆฌํด๋ณด๊ณ ์ ํฉ๋๋ค.
์ฑ ๊ฐ๋ฐ ์ค ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ๊ณผ๋ํ๊ฒ ๋ง๋ค๋ ๊ฒ์ ๋๋ผ๊ณ ๋ฉ๋ชจ๋ฆฌ ๊ทธ๋ํ๋ฅผ ๋ถ์ํ์์ต๋๋ค. ๋ถ์ ๊ฒฐ๊ณผ, ์ฐ๋ฆฌ๊ฐ ์ฌ์ฉํ๊ณ ์๋ ์คํ์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค ํ๋์์ ๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ๊ฒ์ ์๊ฒ ๋์์ต๋๋ค. ํด๋น ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ ์ฐ๊ณ ์๊ณ ๋์ฒดํ๊ธฐ ์ด๋ ต๋ค๊ณ ์๊ฐํ๊ธฐ ๋๋ฌธ์ ์ด์๋ฅผ ์ง์ ํด๊ฒฐํด๋ณด๊ณ ์ ํ์์ต๋๋ค.
๋ฌธ์ ์ ๋ฐ๊ฒฌ
๋ฉ๋ชจ๋ฆฌ ๋ถ์์ ํตํด ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ์๋ค๋ ๊ฒ์ ๋ฐ๊ฒฌํ์ต๋๋ค. ๋ด๊ฐ ์์ฑํ ์ฝ๋์์ ๋ฐ์ํ ๊ฒ์ผ ๊ฑฐ๋ผ ์๊ฐํ์ง๋ง, ์ฌ์ฉํ๊ณ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ๋ฐ์ํ๊ณ ์์์ต๋๋ค. ์ด๋ ๋ถ๋ถ์์ ๋ฐ์ํ๋ ๊ฒ์ธ์ง ํ์ ํ๊ธฐ ์ํด Intruments๋ฅผ ์ฌ์ฉํ์ฌ ๋ถ์ํ์ต๋๋ค.



๋ถ์ ๋ฐ ํด๊ฒฐ๊ณผ์
์ฝ๋๋ฅผ ๋ถ์ ๊ฒฐ๊ณผ ํ์ ํ ์ ๋ณด์ ๋๋ค.
- DispatchWorkItem์ ๊ฐ์ง๊ณ ์๋ ๊ฐ์ฒด DispathWorkHolder
- DispatchQueue ํน์ธ DispatchGroup์์ ์ํํ Task์ ์ ๋ณด๋ฅผ ์บก์ํํ๋ ๊ฐ์ฒด DispatchWorkItem
- ์ง์ ํ ์๊ฐ ์ดํ์ ๋ทฐ๊ฐ ์๋์ผ๋ก ์ฌ๋ผ์ง๊ฒ ํ๋ ํจ์ setupAutohide()
- ๋ทฐ๊ฐ ์ฌ๋ผ์ง๊ฒ ํ๊ธฐ ์ํด setupAutohide() ๋ด๋ถ์์ DispatchWorkHolder๋ฅผ ๋ค์ ์ฐธ์กฐ
๋ง์ง๋ง ํจ์์์ DispatchWorkHolder์ Reference count๋ฅผ ์ฆ๊ฐ์ํค๋ฉด์ retain cycle์ด ๋ฐ์ํ์์ต๋๋ค. ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋ง์ง๋ง ๊ณผ์ ์์ Reference count๋ฅผ ์ฆ๊ฐ์ํค์ง ์์ ๋ฐฉ๋ฒ์ ๊ณต๋ถํ๊ณ , ์๊ฐํด ๋ณด๊ณ , ์ ์ฉํด ๋ณด์์ต๋๋ค.
class -> struct๋ก ๋ณ๊ฒฝ
DispatchWorkHolder๋ class์ด๋ฉฐ ์ฐธ์กฐ ํ์ ์ด๊ธฐ ๋๋ฌธ์ Referece count๋ฅผ ์ฆ๊ฐ์ํต๋๋ค. ๋๋ฌธ์ ๋จ์ํ๊ฒ ๊ฐ ํ์ ์ธ struct๋ก ๋ณ๊ฒฝํ๋ค๋ฉด ํด๊ฒฐํ ์ ์์ง ์์๊น ์๊ฐํ์ฌ DispatchWorkHolder๋ฅผ struct๋ก ๋ฐ๊ฟ๋ณด์์ต๋๋ค.
struct DispatchWorkHolder {
var work: DispatchWorkItem?
}
public struct FullscreenPopup<Item: Equatable, PopupContent: View>: ViewModifier {
.
.
.
/// holder for autohiding dispatch work (to be able to cancel it when needed)
private var dispatchWorkHolder = DispatchWorkHolder()
.
.
.
func setupAutohide() {
// if needed, dispatch autohide and cancel previous one
if let autohideIn = autohideIn {
dispatchWorkHolder.work?.cancel()
// Weak reference to avoid the work item capturing the struct,
// which would create a retain cycle with the work holder itself.
dispatchWorkHolder.work = DispatchWorkItem(block: { [weak isPresentedRef, weak itemRef] in
isPresentedRef?.value.wrappedValue = false
itemRef?.value.wrappedValue = nil
dismissSource = .autohide
})
if sheetPresented, let work = dispatchWorkHolder.work {
DispatchQueue.main.asyncAfter(deadline: .now() + autohideIn, execute: work)
}
}
}
}
ํ์ง๋ง ์ ๊ฐ ๊ฐ๊ณผํ ๊ฒ์ด ์์๋๋ฐ, ๊ตฌ์กฐ์ฒด๋ ๋ด๋ถ ํ๋กํผํฐ์ ๊ฐ์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค. ํ๋กํผํฐ๋ฅผ ๊ฐ์ง๋ FullscreenPopup์ด ๊ตฌ์กฐ์ฒด์ด๊ธฐ ๋๋ฌธ์ ์ด๋ ํด๊ฒฐ ๋ฐฉ๋ฒ์ด ๋ ์ ์์์ต๋๋ค.
weak self
์ฝํ ์ฐธ์กฐ๋ฅผ ํ๋ฉด Reference count๋ฅผ ์ฆ๊ฐ์ํค์ง ์์ต๋๋ค. setupAutohide() ๋ด๋ถ์ ํด๋ก์ ์์ DispatchWorkHolder๋ฅผ ์ฌ์ฐธ์กฐํ๊ธฐ ๋๋ฌธ์ cycle์ด ์๊ธด๋ค๊ณ ์๊ฐํ์์ต๋๋ค. ์ด๋ ํด๋ก์ ๊ตฌ๋ฌธ์์ weak self๋ฅผ ํตํด ํด๊ฒฐํ ์ ์์ ๊ฒ์ด๋ผ ์๊ฐํ์์ต๋๋ค. ํ์ง๋ง ํ์ฌ FullscreenPopup์ ๊ตฌ์กฐ์ฒด์ด๊ณ ์ด๋ ๊ฐ ํ์ ์ด๊ธฐ ๋๋ฌธ์ reference๋ฅผ ๊ฐ์ง์ง ์๊ธฐ ๋๋ฌธ์ self์ ์ฌ์ฉ์ด ๋ถ๊ฐ๋ฅํ์ต๋๋ค.(๋ ๋ง์ฝ ์ฌ์ฉ ๊ฐ๋ฅํ๋๋ผ๋ ์๋ชป ์๊ฐํ ํ์ ํด๊ฒฐํ ์ ์์์ ๊ฒ ๊ฐ์ต๋๋ค.๐ ) ์ด๋ ์ฒซ ๋ฒ์งธ ์๋์์ ๋น์ทํ ์ํฉ์ผ๋ก ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์์ต๋๋ค.
์ง์ ํ ๋น ํด์
Reference count๋ฅผ ์ค์ด๋ ๋ฐฉ๋ฒ ์ค์ ํ๋๋ก ํด๋น ๊ฐ์ฒด๋ฅผ nil๋ก ๋ฐ๊ฟ์ฃผ๋ ๊ฒ์ด ์์ต๋๋ค. ์ต์ข ์ ์ผ๋ก ์๊ฐํ ๋ฐฉ๋ฒ์ผ๋ก ํจ์์ ๋ง์ง๋ง ์์ ์ DispatchWorkIteam์ nil๋ก ๋ง๋ค์ด์ฃผ์์ต๋๋ค.
func setupAutohide() {
// if needed, dispatch autohide and cancel previous one
if let autohideIn = autohideIn {
dispatchWorkHolder.work?.cancel()
// Weak reference to avoid the work item capturing the struct,
// which would create a retain cycle with the work holder itself.
dispatchWorkHolder.work = DispatchWorkItem(block: { [weak isPresentedRef, weak itemRef] in
isPresentedRef?.value.wrappedValue = false
itemRef?.value.wrappedValue = nil
dismissSource = .autohide
dispatchWorkHolder.work = nil
})
if sheetPresented, let work = dispatchWorkHolder.work {
DispatchQueue.main.asyncAfter(deadline: .now() + autohideIn, execute: work)
}
}
}
์ด ๋ฐฉ๋ฒ์ ํตํด ํด๋น ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์์ต๋๋ค.
๊ฒฐ๋ก ๋ฐ ํ๊ธฐ
๋น๋ก ์ฝ๋ ํ ์ค๋ก ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์์ง๋ง, ํด๊ฒฐํ๋ ๊ณผ์ ์์ ์ฝ๋ ๋ถ์, ๋ฉ๋ชจ๋ฆฌ ๊ด๋ จ, ์ฐธ์กฐ ๊ด๋ จ ๊ณต๋ถ๋ก๋ง 1์ฃผ์ผ์ ์ฌ์ฉํ ๊ฒ ๊ฐ์ต๋๋ค. ํฌ๊ธฐํ ๊น๋ ์๊ฐํ์ง๋ง ํ ์ ์์ ๊ฒ์ด๋ผ๋ ์๊ฐ๊ณผ ํด๋ด๊ณ ๋ง๊ฒ ๋ค๋ ์ง๋ ํ๋๋ก ๊ณ์ ์งํํ๋ ๊ฒ ๊ฐ์ต๋๋ค. ์ข์ ๋ฐฉ๋ฒ์ธ์ง๋ ๋ชจ๋ฅด๊ฒ ์ง๋ง ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์๊ณ ๊ฒฐ๊ณผ์ ์ผ๋ก ์์ฒญ๋ ๊ณต๋ถ๊ฐ ๋์์ต๋๋ค. ๊ฐ๋ฐ์๋ก์ ํ ์ธต ์ฑ์ฅํ๊ณ , ๊ฐ๋ฐํ๋ ๊ฒ์ด ๋์ฑ ์ฌ๋ฐ์ด์ง๋ ๊ฒฝํ์ด์์ต๋๋ค.

https://github.com/exyte/PopupView
GitHub - exyte/PopupView: Toasts and popups library written with SwiftUI
Toasts and popups library written with SwiftUI. Contribute to exyte/PopupView development by creating an account on GitHub.
github.com
