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 အေၾကာင္း အနည္းငယ္ေလာက္ နားလည္ေလာက္ပါၿပီ။


 
2 Kudos
Don't
move!

Leave a Reply