Delegate in Swift

iOS development လုပ်သည့်အခါမှာတော့ Delegate ကို မဖြစ်မနေ သိဖို့လိုအပ်ပါတယ်။ Delegate ကတော့ Table View ကို အသုံးပြုသည့်သူတွေ အနေနဲ့ သိပါလိမ့်မယ်။ သို့ပေမယ့် အခုမှ စပြီးလေ့လာသူတွေ အနေနဲ့ Delegate ကို မသိပဲ table view ကို အသုံးပြုနေကြသူတွေလည်း ရှိပါလိမ့်မယ်။

Table View မှာ အဓိက အားဖြင့် Delegate နဲ့ Data Source ဆိုပြီး ပါပါတယ်။ Data Source ကတော့ Rows ဘယ်နှစ်ခု ပါမလဲ ၊ Section ဘယ်နှစ်ခု ပါမလဲ အတွက် အသုံးပြုပါတယ်။ Delegate ကတော့ Table မှာ Cell ကို Select လုပ်လိုက်လားဆိုပြီး တော့ ပို့ပေးပါတယ်။ ကျွန်တော်တို့ Table View ထက်စာရင် ကိုယ်ပိုင် Delegate Example လေး ဖန်တီးကြည့်ရအောင်။
class World {
   var number = 1
    func growTheTree() {
        print("Grow The Tree");
        number += 1
    }
}
အခု World ဆိုတဲ့ class လေး တစ်ခု ဆောက်ထားတယ်။ growTheTree ဆိုတဲ့ function လေးပါပါတယ်။ အဲဒီ အထဲမှာတော့ ပုံမှန် print လေး လုပ်ထားတာပဲ ရှိပါတယ်။ အဲဒီ class လေးကို သုံးကြည့်ရအောင်။
class MyWorld {
    
    func run() {
        let earth = World()
        earth.growTheTree()
    }
    
}
let world = MyWorld()
world.run()

အဲဒါ ဆိုရင်တော့ Grow The Tree ဆိုတာလေးကို သွားပေါ်ပါလိမ့်မယ်။ အကယ်၍ growTheTree မှာ ရေးထားတာက synchronize မဟုတ်ပဲ asynchronous ဖြစ်ဖြစ် Thread နဲ့ ဖြစ်ဖြစ် ဒါမှမဟုတ် event တစ်ခုခု ဖြစ်ပြီးမှသာ growTheTree က ပြီးမြောက်သွားလိမ့်မယ်။ အဲဒီလို အခါတွေမှာ ကျွန်တော်တို့တွေ Delegate ကို အသုံးပြုနိုင်ပါတယ်။ Delegate အတွက် protocol လေး တစ်ခု ဖန်တီးရအောင်။
protocol WorldDelegate {
    func didTreeGrow(number: Int);
}
WorldDelegate ထဲမှာ didTreeGrow ဆိုတာပါပါတယ်။ number ကတော့ ဘယ်နှစ်ခုမြောက်လဲ ဆိုတာကို သိဖို့ အတွက်ပါ။ protocol ကို ဖန်တီးထားပြီး implement လုပ်လိုက်ရင် အဲဒီ function မဖြစ်မနေ ပါကို ပါရမယ် လို့ ဆိုလိုတာပါ။
class World {
    
    var number = 1
    var delegate: WorldDelegate?
    func growTheTree() {
        print("Grow The Tree")
        
        if let callback = delegate {
            callback.didTreeGrow(number: number)
        }

        number += 1
        
    }
}
အဲဒီမှာတော့ ကျွန်တော် delegate variable လေး တစ်ခု ဖန်တီးထားပါတယ်။ အဲဒီ object က WorldDelegate ဖြစ်ရမယ်လို့ ဆိုထားပါတယ်။ WorldDelegate ဖြစ်ရမယ် ဆိုတာကြောင့် didTreeGrow ဆိုတဲ့ function မဖြစ်မနေ ပါရမယ် ဆိုတာကို သိသွားပါပြီ။
if let callback = delegate {
    callback.didTreeGrow(number: number)
}
ဆိုတာက delegate ကို optional ပေးထားလို့ပါ။ ဒါကြောင့် delegate က ပါတယ်လည်း ဖြစ်နိုင်သလို မပါတာလည်း ဖြစ်နိုင်တယ်။ ပါခဲ့မှ အလုပ်လုပ်မယ်ဆိုပြီး အဲလို ရေးထားတာပါ။ အဲဒါကို တိုသွားအောင် အောက်ကလို ရေးလို့ရပါတယ်။
delegate?.didTreeGrow(number: number)
ကဲ ဒါဆိုရင် ကျွန်တော်တို့တွေ delegate ကို စမ်းသုံးကြည့်အောင်။ MyWorld class ကို အောက်ကလို ပြောင်းလိုက်မယ်။
class MyWorld {
    
    func run() {
        let earth = World()
        earth.delegate = self
        earth.growTheTree()
    }
    
}

extension MyWorld: WorldDelegate {
    func didTreeGrow(number: Int) {
        print("Tree No. \(number)")
    }
}
delegate ကို self ဆိုပြီး ပေးလိုက်တယ်။ လက်ရှိ class မှာ protocol ကို implement မလုပ်ပဲ extension လုပ်ပြီးတော့ implement လုပ်ပါတယ်။ နောက်ပိုင်း ကျွန်တော် swift နဲ့ ရေးသည့်အခါမှာ အဲလိုမျိုး delegate အတွက် သီးသန့် လေးတွေ ခွဲထုတ်ပြီးတော့ ရေးတတ်ပါတယ်။ code ဖတ်သည့် အခါမှာ ရှင်းအောင်လို့ပါ။ Code တစ်ခုလုံးကို ပြန်ကြည့်ရအောင်။
protocol WorldDelegate {
    func didTreeGrow(number: Int);
}

class World {
    
    var number = 1
    var delegate: WorldDelegate?
    func growTheTree() {
        print("Grow The Tree")

        delegate?.didTreeGrow(number: number)
        number += 1
        
    }
}

class MyWorld {
    
    func run() {
        let earth = World()
        earth.delegate = self
        earth.growTheTree()
    }
    
}

extension MyWorld: WorldDelegate {
    func didTreeGrow(number: Int) {
        print("Tree No. \(number)")
    }
}

let world = MyWorld()
world.run()

အဲဒီ code လေးကို playground မှာ run လိုက်ရင် Grow The Tree နှင့် Tree No. 1 ဆိုပြီး ပေါ်လာပါလိမ့်မယ်။ Delegate ကို ပုံမှန် အားဖြင့် event တစ်ခုခု လုပ်လိုက်တယ် ဆိုတာကို အကြောင်းကြားသည့် ပုံစံအနေနဲ့ အသုံးပြုကြပါတယ်။ ဥပမာ TableView မှာဆိုရင် cell တစ်ခုခု ကို select လုပ်လိုက်တယ်။ Scroll View မှာ ဆိုရင် Scroll ဆွဲလိုက်သည့် event ဖြစ်သွားတယ်။ စတာတွေကို delegate နဲ့ ပြန်ပို့ ကြပါတယ်။ နည်းနည်းလေး အဆင့်ထပ်မြှင့် လိုက်ရအောင်။ တစ်ခါတစ်လေ တစ်ချို့ function တွေက ပါလည်း ဖြစ်တယ်။ မပါလည်း ဖြစ်တယ်။ ဥပမာ ၊ အခု လို code မှာ ဆိုရင် beforeTreeGrow func က ပါလည်း ဖြစ်တယ် မပါလည်း ဖြစ်တယ်ဆိုပါစို့။ optional တွေ အတွက်ကတော့ @objc နဲ့ တွဲသုံးရပြီးတော့ Foundation framework လိုအပ်ပါတယ်။
import Foundation

@objc protocol WorldDelegate {
    func didTreeGrow(number: Int);
    @objc optional func beforeTreeGrow(number: Int);
}
ဒီ code လေးက ဆိုရင်တော့ beforeTreeGrow ဆိုတာကတော့ optional function ပါ။ protocol မှာ ဒီအတိုင်း optional မရေးရပဲ @objc လေးနဲ့ တွဲဖို့ လိုပါတယ်။
class World {
    
    var number = 1
    var delegate: WorldDelegate?
    func growTheTree() {
        
        delegate?.beforeTreeGrow?(number: number)
        print("Grow The Tree")     
        delegate?.didTreeGrow(number: number)
        number += 1
        
    }
}
Optional ဖြစ်သည့် အတွက်ကြောင့် function ကို
delegate?.beforeTreeGrow?(number: number)
လေးနဲ့ ရေးထားတာကို တွေ့နိုင်ပါလိမ့်မယ်။
extension MyWorld: WorldDelegate {
    
    func beforeTreeGrow(number: Int) {
        print("Before \(number)")
    }
    func didTreeGrow(number: Int) {
        print("Tree No. \(number)")
    }
}
func beforeTreeGrow(number: Int) { ဆိုတဲ့ function က ပါလည်း ဖြစ်သလို မပါလည်း ဖြစ်တာကို တွေ့နိုင်ပါတယ်။ ပါလာခဲ့ရင်တော့ print မထုတ်ခင်မှာ ပြပြီးတော့ မပါလာခင်ရင်လည်း ဘာ error မှ ပြမှာ မဟုတ်ပါဘူး။ ဒီလောက်ဆိုရင် Delegate အကြောင်း အနည်းငယ်လောက် နားလည်လောက်ပါပြီ။

Leave a Reply