ํฐ์คํ ๋ฆฌ ๋ทฐ
๐ Actor (1) ์ฝ์ผ๋ฌ๊ฐ๊ธฐ
# Actor ํน์ง ๋ณต์ต ๐
- Actor๋ ๊ทธ๋ฅ Swift์ ์๋ก์ด ํ์ ์. ํด๋์ค์ ๊ฐ์ฅ ์ ์ฌ.
- Swift์ ๋ค๋ฅธ ๋ชจ๋ ํ์ ๋ค๊ณผ ๋๊ฐ์ด ํ๋กํผํฐ, ๋ฉ์๋, ์ด๋์ ๋ผ์ด์ , subscripts ๋ฑ์ ๊ฐ์ง ์ ์์.
- ํ๋กํ ์ฝ ์ค์, Extension ์ญ์ ์๊ฐ๋ฅ
- ์ฐธ์กฐํ์ like class
- ํด๋์ค์ ๋ฌ๋ฆฌ Actor๋ ํ๋ฒ์ ํ๋์ ์์ ๋ง ๋ณ๊ฒฝ ๊ฐ๋ฅํ ์ํ(mutable state)์ ์ ๊ทผํ ์ ์๋๋ก ํ์ฉ.
- ํด๋์ค์ ๋ฌ๋ฆฌ ์์์ ์ง์ํ์ง ์์.
# Actor isolation
์ฐ๋ฆฌ๊ฐ ์ฌ์ค immutable state๋ฉด Actor๋ฅผ ์ธ ํ์๋ ์์์์?
๊ทผ๋ฐ ์ง๊ธ (Shared) mutable state์ฌ์ ์ง๊ธ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ฌ์ง๊ฐ ์๋๊ฑฐใ ใ
๊ทธ๋์ ์ฐ๋ฆฌ๊ฐ Actor๋ผ๋ ๊ฑธ ์ฐ๋๊ฑฐ๊ณ .
Actor๊ฐ mutable state์ ๋์์ ์ ๊ทผํ์ง ์๋๋ก ํ๋๊น! Swift๊ฐ ๊ทผ๋ณธ์ ์ผ๋ก ๋ณด์ฆํ๋๊น!
๐คท: ๊ทผ๋ฐ Actor ๋๊ฐ ๋ญ๋ฐ,,๋๊ฐ ์ด๋ป๊ฒ ๋ณดํธํ๊ฒ ๋ค๋๊ฑด๋ฐ..๊ทธ๊ฑฐ ์ด๋ป๊ฒ ํ๋๊ฑด๋ฐ
๐ง๐ป: Actor isolation. Actor isolation์ Actor๊ฐ mutable state๋ฅผ ๋ณดํธํ๋ ๋ฐฉ๋ฒ์.
๐คท : ์ ํํ ์ด๋ป๊ฒ ๋ณดํธํ๋๋
์๋ฅผ ๋ค์ด๋ณด์. BankAccount๋ผ๋ Actor๊ฐ ์์.
actor BankAccount {
let accountNumber: Int
var balance: Double
init(accountNumber: Int, initialDeposit: Double) {
self.accountNumber = accountNumber
self.balance = initialDeposit
}
}
๊ทธ๋ฆฌ๊ณ BankAccount์ extensionํ์ด
extension BankAccount {
enum BankError: Error {
case insufficientFunds
}
func transfer(amount: Double, to other: BankAccount) throws {
if amount > self.balance {
throw BankError.insufficientFunds
}
print("Transferring \(amount) from \(accountNumber) to \(other.accountNumber)")
self.balance = balance - amount
other.balance = other.balance + amount // error: actor-isolated property 'balance' can only be referenced on 'self'
}
}
extension์๋ transfer(amount: to :) ๋ฉ์๋๊ฐ ์์.
func transfer(amount: Double, to other: BankAccount) throws {
if amount > self.balance {
throw BankError.insufficientFunds
}
print("Transferring \(amount) from \(accountNumber) to \(other.accountNumber)")
self.balance = balance - amount โ
other.balance = other.balance + amount โ
}
์ balance๋ฅผ ์ ๋ฐ์ดํธ ์ํค๋ ๊ณณ์ ๋ณด์.
์ ๋ง์ฝ์ BankAccount๊ฐ class์์ผ๋ฉด
1. ์ ์ฝ๋๋ ๋ฌธ์ ๊ฐ ์๊ณ == ์ปดํ์ผ ์๋ฌ๊ฐ ์๋๊ณ
2. concurrent code์์ data races๋ฅผ ๋ฐ์์ํฌ ์ ์์.
์๋? balance๋ฅผ ์ ๋ฐ์ดํธ ์ํค๋๊น.
๊ทผ๋ฐ BankAccount๊ฐ ์ง๊ธ actor์์??
func transfer(amount: Double, to other: BankAccount) throws {
if amount > self.balance {
throw BankError.insufficientFunds
}
print("Transferring \(amount) from \(accountNumber) to \(other.accountNumber)")
self.balance = balance - amount โ
other.balance = other.balance + amount ๐จ // error: actor-isolated property 'balance' can only be referenced on 'self'
}
other.balance๋ฅผ ์ ๋ฐ์ดํธ ์ํค๋ ์ชฝ์ด ์ปดํ์ผ์๋ฌ๊ฐ ๋จ.
์๋๋ฉด balance๋ self์์๋ง ์ฐธ์กฐ๋ ์ ์๊ธฐ ๋๋ฌธ!!!!!
other.balance ์ด๋ ๊ฒ ์ฐธ์กฐ๋งํด๋ ์๋ฌ๊ฐ๋จ.
์๋ฌ๋ฅผ ์์ธํ ๋ณด์
actor-isolated property 'balance' can only be referenced on 'self'
1. actor-isolated property 'balance'
๐: balance ํ๋กํผํฐ๊ฐ actor-isolated property์ธ๊ฐ๋ณด๊ตฐ..
๐ง๐ป : (๋๋ฅ) ์ฌ์ค์ ๋๋ค.
actor๋ด์ ์ ์๋
- stored, computed instance properties
- instance methods
- instance subscripts
๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ actor-isolated ์ํ์ด๋ค.
2. can only be referenced on 'self'
actor-isolated ์น๊ตฌ๋ค์ ์ฐ๊ฒฐ๋๊ฑฐ๋ "๊ฒฉ๋ฆฌ๋" ํน์ actor๋ด์์ ์ ๊ทผํ ์ ์๋๋ฐ, ๊ทธ๊ฒ self๋ค.
๊ทธ๋ฌ๋๊น actor-isolated ์น๊ตฌ๋ค์ ๊ธฐ๋ณธ์ ์ผ๋ก self๋ฅผ ํตํด์๋ง ์ ๊ทผ์ด ๊ฐ๋ฅํ๋ค๋ ๋ป์ด๋ค.
ํน1. actor-isolated ์ ์๋ค์ ๋ค๋ฅธ actor-isolated ์ ์๋ค์ ์์ ๋กญ๊ฒ ์ฐธ์กฐ ํ ์ ์๋ค.
ํน2. actor-isolated๊ฐ ์๋ ์ ์๋ค์ actor-isolated ์ ์๋ค์ ๋๊ธฐ์ ์ผ๋ก ์ ๊ทผํ ์ ์๋ค.
# cross-actor reference
actor ์ธ๋ถ์์ actor-isolated ์ ์์ ๋ํด ์ฐธ์กฐํ๋ ๊ฒ์ cross-actor reference๋ผ๊ณ ํ๋ค.
์ด๋ฌํ ์ฐธ์กฐ๋ 2๊ฐ์ง ๋ฐฉ๋ฒ์ค ํ๋๋ก ํ์ฉ๋๋ค.
1. ๋ถ๋ณ ์ํ์ ๋ํ cross-actor reference.
actor๊ฐ ์ ์๋ ๋์ผํ ๋ชจ๋์ ์ด๋ ๊ณณ์์๋ ํญ์ ํ์ฉ.
(ํ ๋ฒ ์ด๊ธฐํ๋๋ฉด ํด๋น ์ํ๋ actor ๋ด๋ถ์์๋ , ์ธ๋ถ์์๋ ์์ ํ ์ ์๊ธฐ ๋๋ฌธ์)
๐: ์ง๋ฌธ!
actor BankAccount {
let accountNumber: Int
var balance: Double
init(accountNumber: Int, initialDeposit: Double) {
self.accountNumber = accountNumber
self.balance = initialDeposit
}
}
BankAccount์๋ accountNumer๋ balance๊ฐ ์์์!
์๊น
other.balance ๐จ // error: actor-isolated property 'balance' can only be referenced on 'self'
์ด๋ ๊ฒ balance๋ฅผ ์ฐธ์กฐ๋ง ํด๋ ์๋ฌ๋ฌ์ผ๋๊น
ohter.accountNumber
์ด๊ฒ๋ ์๋ฌ๋๊ฒ ๋ค?
๐ง๐ป: ์๋๋ค.
func transfer(amount: Double, to other: BankAccount) throws {
if amount > self.balance {
throw BankError.insufficientFunds
}
print("Transferring \(amount) from \(accountNumber) to \(other.accountNumber)")
self.balance = balance - amount โ
other.accountNumber โ
}
other์ accountNumber์ ์ ๊ทผํ๋๊ฑด ๊ด์ฐฎ์.
์๋?
accountNumber๋ let์ผ๋ก ์ ์ธ๋์ด์๊ธฐ ๋๋ฌธ์ ๋ถ๋ณ ์ํ์ ๋ํ cross-actor reference์ ํด๋น๋๋ค.
๐จ [์ฃผ์] ๐จ
actor๊ฐ ์ ์๋ ๋์ผํ ๋ชจ๋์ ์ด๋ ๊ณณ์์๋ ํญ์ ํ์ฉ.
์ฆ, actor๊ฐ ์ ์๋ ๋ชจ๋์ด ์๋ ๋ค๋ฅธ ๋ชจ๋์์๋ ํ์ฉ์ด ์๋๋ค๋ ๋ป์ด๋ค.
์๋ฅผ ๋ค์ด๋ณด์.
public actor BankAccount {
public let accountNumber: Int
public var balance: Double
public init(accountNumber: Int, initialDeposit: Double) {
self.accountNumber = accountNumber
self.balance = initialDeposit
}
}
// Same module
public class MyStaticLibrary {
public init() {
let account = BankAccount(accountNumber: 1, initialDeposit: 10)
print(account.accountNumber) โ
}
}
์ด๋ ๊ฒ ๊ฐ์ ๋ชจ๋์์ ์ ์๋์ด์์ผ๋ฉด accountNumber๊ฐ let์ด๋ฏ๋ก ์ ๊ทผ์ด ๊ฐ๋ฅํ๋ค.
ํ์ง๋ง, ์ธ๋ถ ๋ชจ๋์์๋
func outside_moudle_method() โ
async โ
{
let account = BankAccount(accountNumber: 1, initialDeposit: 10)
print(โ
await โ
account.accountNumber) โ
}
๋ฐ๋์ ๋น๋๊ธฐ ํธ์ถ๋ก ์ฐธ์กฐํด์ผํ๋ค.
๐คท : ์๋ ์ ์ด๋ฐ..?
๐ง๐ป : ๋ง์ฝ์ BankAccount๊ฐ ์ ์๋์ด์๋ ๋ชจ๋์ ์ฌ์ฉํ๋ ํด๋ผ์ด์ธํธ๊ฐ ์๋ค๊ณ ์ณ๋ณด์.
๋ด๊ฐ accountNumber๋ฅผ let์ผ๋ก ์ ์ธํด์ ํด๋ผ์ด์ธํธ ์ฝ๋์๋
print(account.accountNumber) โ
๊ทธ๋ฅ ์ด๋ฐ ์ฝ๋๊ฐ ์์ด.
๊ทผ๋ฐ ๋ด๊ฐ ๋ชจ์ข ์ ์ด์ ๋ก ์ธํด์ accountNumber๋ฅผ var๋ก ๋ฐ๊ฟ์ผํ๋ค๊ณ ์ณ๋ณด์?
๊ทผ๋ฐ var๋ ๋น๋๊ธฐ ํธ์ถ๋ง ๋ผ (์ธ๋ถ์์ ์ฐธ์กฐํด์ผํ๋๊น)
์ฆ, BankAccount๋ชจ๋์ ์ฐ๋ ํด๋ผ์ด์ธํธ ์ฝ๋๊ฐ ์ ๋ถ ๋ฐ๋์ด์ผํ๋ค๋ ์๋ฆฌ..
๊ทธ๋ฌ๋๊น ๊ทธ๋ฐ ์ผ์ด ๋ฐ์ํ์ง ์๋๋ก, ์ฆ ํด๋ผ์ด์ธํธ๋ ์ํฅ์ ๋ฐ์ง ์๋๋ก
๋ชจ๋ ์ธ๋ถ์์๋ let์ด๋ var๋ ๋น๋๊ธฐ๋ก ์ฐธ์กฐํด์ผํ๋ค๋๊ฑฐ!
1. ๋ถ๋ณ ์ํ์ ๋ํ cross-actor reference. โ
2. ๋น๋๊ธฐ ํจ์ ํธ์ถ๋ก ์ํ๋๋ ํ์
๋น๋๊ธฐ ํจ์ ํธ์ถ์ actor๊ฐ ์์ ํ๊ฒ ์ํํ ์ ์์ ๋ ํด๋น์์ ์ ์คํํ๋๋ก ์์ฒญํ๋ "๋ฉ์์ง"๋ก ๋ฐ๋๋ค.
์ด๋ฌํ ๋ฉ์์ง๋ actor์ ๋ฉ์ผ๋ฐ์ค์ ์ ์ฅ๋๋ฉฐ,
๋น๋๊ธฐ ํจ์ ํธ์ถ์ ์์ํ ํธ์ถ์๋ actor๊ฐ ๋ฉ์ผ๋ฐ์ค์์ ํด๋น ๋ฉ์์ง๋ฅผ ์ฒ๋ฆฌํ ์ ์์๋ ๊น์ง ์ผ์์ค๋จ๋ ์ ์๋ค.
actor๋ ๋ฉ์ผ๋ฐ์ค์ ๋ฉ์์ง๋ฅผ ์์ฐจ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ฏ๋ก, ๊ถ๊ทน์ ์ผ๋ก actor๋ 2๊ฐ ์ด์์ ๋์์ ์คํ๋๋ ์์ ์ ์คํํ ์ ์๋ค.
์ฆ, ์ฝ๋ ์์ฒด์ ๋์์ฑ์ด ์์ด์ง๊ฒ ๋๋ฌธ์ Data race๊ฐ ๋ฐ์ํ์ง ์๊ฒ ๋๋ค.
์, ์๋ฅผ ๋ค์ด๋ณด์.
๋ด๊ฐ ์ด์ฒด๋ฅผ ํ์ผ๋๊น
func transfer(amount: Double, to other: BankAccount) throws {
if amount > self.balance {
throw BankError.insufficientFunds
}
print("Transferring \(amount) from \(accountNumber) to \(other.accountNumber)")
self.balance = balance - amount โ
other.balance = other.balance + amount ๐จ // error: actor-isolated property 'balance' can only be referenced on 'self'
}
๋ด ์์ก์ ์ด์ฒดํ ์ ๋งํผ ์ค์ด๋ค์ด์ผ ํ๊ณ ,
๋ด๊ฐ ์ด์ฒดํ ๋ค๋ฅธ ๊ณ์ข์ ์์ก์ ๋ด๊ฐ ์ด์ฒดํ ์๋งํผ ๋์ด๋์ผํ๋ค.
ํ์ง๋ง, balance๋ actor-isolated ํ๋กํผํฐ์ด๊ธฐ ๋๋ฌธ์..self๊ฐ ์๋ other๋ก balance์ ์ ๊ทผ์ ๋ชปํ๋ ์ํฉ.
์ด๊ฑธ 2๋ฒ์ผ๋ก ํด๊ฒฐํด๋ณด์.
extension BankAccount {
func deposit(amount: Double) โ
async โ
{
assert(amount >= 0)
balance = balance + amount
}
}
๋จผ์ BankAccount์ deposit์ด๋ผ๋ ๋ฉ์๋๋ฅผ ๋ง๋๋๋ฐ, async๋ก ์ ์ธํด์ค๋ค.
๊ทธ๋ฆฌ๊ณ
func transfer(amount: Double, to other: BankAccount) โ
async โ
throws {
if amount > self.balance {
throw BankError.insufficientFunds
}
print("Transferring \(amount) from \(accountNumber) to \(other.accountNumber)")
self.balance = balance - amount
await other.deposit(amount: amount) โ
}
other์ deposit์ ํธ์ถํด์ค๋ค.
deposit์ด async๋ก ์ ์๋์ด์์ผ๋ await์ผ๋ก ํธ์ถํด์ฃผ์.
transfer๋ด์์ async๋ฉ์๋๋ฅผ ํธ์ถํด์ผํ๊ธฐ ๋๋ฌธ์ transfer๋ async๋ก ์ ์ํด์ค์ผํ๋ค.
์์์ ๋ฉ์์ง/๋ฉ์ผ๋ฐ์ค๋ก ์๋ฅผ ๋ค์์ผ๋
await other.deposit(amount: amount) โ
์ด๊ฒ์ ๋ฉ์์ง/๋ฉ์ผ๋ฐ์ค๋ก ๋ฐ๊ฟ ๋งํด๋ณด์.
1. deposit์ด ๋ฉ์์ง๊ฐ ๋๋ฉฐ
2. other actor์ ๋ฉ์ผ๋ฐ์ค์ ๋ค์ด๊ฐ๊ฒ ๋๋ค.
3. other actor๋ ๋ฉ์ผ๋ฐ์ค์์ ์์ ์ ๊ฒ์ํ์ฌ(retrieves the operation) ์คํํ๋ค.
4. other์ balance๊ฐ ์ ๋ฐ์ดํธ ๋๋ค.
cross-actor reference๋ฅผ ํ๋ ๋ฐฉ๋ฒ์ ๋ํด์ ์ ๋ถ ์์๋ณด์๋ค.
1. ๋ถ๋ณ ์ํ์ ๋ํ cross-actor reference. โ
2. ๋น๋๊ธฐ ํจ์ ํธ์ถ๋ก ์ํ๋๋ ํ์ โ
# Compile-time actor-isolation checking
์ปดํ์ผ ์๊ฐ์ ์ด๋ฃจ์ด์ง๋ actor-isolation checking์
1. cross-actor references์ธ์ง ํ์ธํ๊ณ
2. ์ด๋ฌํ ์ฐธ์กฐ๊ฐ ์์์ ์ค๋ช ํ 2๊ฐ์ง ๋ฉ์ปค๋์ฆ ์ค ํ๋๋ฅผ ์ฌ์ฉํ๋๋ก ํ๋ค.
์ด๋ ๊ฒ ํ๋ฉด actor ์ธ๋ถ์ ์ฝ๋๊ฐ actor์ mutable state๋ฅผ ๋ฐฉํดํ์ง ์๋๋ค.
๊ทธ๋ฌ๋๊น ์ด๊ฒ์ด!!!!!!!!!!!!!
์ง์ง ์ด๊ฑธ ๊ฐ๊ธธ๊ฒ ๋งํ๋๋ฐ, ์ด๊ฒ Actor๊ฐ mutable state๋ฅผ ๋ณดํธํ๋ ๋ฐฉ๋ฒ์ธ๊ฑฐ.
# Advanced
์์์ deposit์ async๋ก ๊ตฌํํ์๋ค.
extension BankAccount {
func deposit(amount: Double) โ
async โ
{
assert(amount >= 0)
balance = balance + amount
}
}
ํ์ง๋ง ์ ๋ณด๋ฉด, deposit์ async๋ก ๊ตฌํ ๋ ํ์๋ ์๋ค.
(deposit์์์ await๋ฅผ ํธ์ถํ๋๊ฒ๋ ์๋๋ผ์)
๋ฐ๋ผ์ ์ด ๊ฒฝ์ฐ์๋
extension BankAccount {
func deposit(amount: Double) {
assert(amount >= 0)
balance = balance + amount
}
}
๋๊ธฐํจ์(sync)๋ก ์ ์ํ๋ ๊ฒ์ด ๋ ๋ซ๋ค.
๐คท: ์๋
await other.deposit(amount: amount) โ
์ด๋ ๊ฒ await ํ๋๋ฐ, async๋ก ์ ์ธ๋์ด์ผ ํ๋๊ฑฐ ์๋์ผ? ์ปดํ์ผ ์๋ฌ ์๋?
๐ง๐ป : ใ ใ ์๋..
func non_async_method() {}
func zedd() async {
await non_async_method()
}
async ์์์ await + sync ํจ์๋ฅผ ํธ์ถํ๋๊ฑด ์ปดํ์ผ ์๋ฌ์ ํด๋น์ด ์๋๋ค.
๋ค๋ง
No 'async' operations occur within 'await' expression
์ด๋ฐ ๊ฒฝ๊ณ ๊ฐ ๋ฐ ๋ฟ...
await other.deposit(amount: amount) โ
extension BankAccount {
func deposit(amount: Double) {
assert(amount >= 0)
balance = balance + amount
}
}
์๊ฑด ๊ทธ๋ฐ ๊ฒฝ๊ณ ๋ ์๋ฌ๋ค.
์ด์ ๋ฅผ ์์๋ณด์.
์์์ ๊ณ์ ๋ดค๋ฏ์ด BankAccount๋ actor๋ก ์ ์๋์ด์๋ค.
actor BankAccount {..}
extension BankAccount {
func deposit(amount: Double) {
assert(amount >= 0)
balance = balance + amount
}
}
deposit์ ๊ทธ๋ฐ actor ํ์ ์์ sync ๋ฉ์๋์ด๋ค.
sync ๋ฉ์๋์ฌ๋
actor ์ธ๋ถ์์๋ ์๋์ฒ๋ผ await ํค์๋์ ํจ๊ป ์จ์ผํ์ง๋ง,
// actor ์ธ๋ถ
let account = BankAccount(accountNumber: 1, initialDeposit: 100)
await account.deposit(amount: 10)
actor ๋ด๋ถ์์๋ ๋๊ธฐ์ ์ผ๋ก ํธ์ถํ ์ ์๋ค. ์ฆ await ํค์๋๋ฅผ ๊ฐ์ด ์จ์ฃผ์ง ์์๋ ๋๋ค.
ํ์ง๋ง cross-actor reference ์ผ๋๋!!!!!!!! ๋น๋๊ธฐ ํธ์ถ์ด ํ์ํ๋ค. ์ฆ, await๊ณผ ํจ๊ป ์จ์ผํ๋ค.
1. actor ๋ด๋ถ์์๋ ๋๊ธฐ์ ์ผ๋ก ํธ์ถํ ์ ์๋ค.
extension BankAccount {
// Pass go and collect $200
func passGo() {
self.deposit(amount: 200.0) // synchronous is okay because `self` is isolated
}
}
2. cross-actor reference ์ผ๋๋ ๋น๋๊ธฐ ํธ์ถ์ด ํ์ํ๋ค.
func transfer(amount: Double, to other: BankAccount) โ
async โ
throws {
if amount > self.balance {
throw BankError.insufficientFunds
}
print("Transferring \(amount) from \(accountNumber) to \(other.accountNumber)")
self.balance = balance - amount
await other.deposit(amount: amount) โ
}
์ฌ์ค Actor์ ์กด์ฌ๋ ๋๋ฌด๋๋..ํฐ ๋ณํ์ด๊ธฐ ๋๋ฌธ์
WWDC 21 Protect mutable state with Swift actors๋ฅผ ๋ณด๋ฉด์..๊ฝค ์ค๋ซ๋์ ์จ์ค๋ ๊ธ์ธ๋ฐ์.
์ Actor isolation์ ๋ถ๋ชํ์ ใ ใ ์ง์ง ๋๋ฌด์ง ์ดํด๊ฐ ์๊ฐ์ ๊ฐ์งฑ๋๋ค..์ํด ** ์ด์ํ๋ก ๋ช์ฃผ...
swift-evolution์ actor proposal์ ๋ณด๋๊น ์ด๋์ ๋ ์ดํด๊ฐ ๊ฐ๋๋ค.
๐ค ์ฌ์ ํ ํท๊ฐ๋ฆฌ๋ ๋ถ๋ถ์ ์์ง๋ง ใ ใ ...
ํน์ ํ๋ฆฐ์ ์ด ์๋ค๋ฉด ๋๊ธ ๋ฌ์์ฃผ์ธ์ ๐โ๏ธ
[๋ค์ ๊ธ ์ฝ์ผ๋ฌ๊ฐ๊ธฐ]
Actor (3) - isolated parameter / nonisolated keyword
'Swift > Concurrency' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Combine โ Swift Concurrency(async/await)๋ก ๋ฐ๊พธ๊ธฐ (feat. ๋๋์ ) (3) | 2022.01.25 |
---|---|
Actor (4) - Sendable (3) | 2021.10.11 |
Swift ) Actor (3) - isolated parameter / nonisolated keyword (1) | 2021.08.29 |
Swift ) Actor (1) (5) | 2021.08.22 |
[Swift Concurrency] Async/await (11) | 2021.03.25 |
- np-complete
- fastlane
- github
- WWDC
- ์ ์ด์จ ํ์ฑ
- ํ๊ณ
- ์ค์ํํธ ๋ฌธ๋ฒ
- ํผ์๋ ธ
- ์ค์ํํธ
- Swift
- FLUTTER
- Git
- Accessibility
- IOS
- swift3
- swift delegate
- swift array
- swift ๊ณต๋ถ
- np-hard
- Xcode
- actor
- ios 13
- swift sort
- Combine
- UIBezierPath
- swift tutorial
- SwiftUI
- WKWebView
- iOS delegate
- WidgetKit
- Total
- Today
- Yesterday