ہیلو! میرا نام کیرل فامین ہے، اور میں ایک iOS ڈویلپر ہوں۔
آج، میں سوئفٹ میں ابتداء کے طور پر اس طرح کے ایک سادہ موضوع کا اچھی طرح سے جائزہ لینا چاہتا ہوں۔ اس کی ظاہری سادگی کے باوجود، بعض اوقات اس موضوع کی مکمل تفہیم کی کمی مایوس کن غلطیوں کا باعث بنتی ہے جسے کوئی شخص تفصیلات میں جانے کے بغیر جلدی ٹھیک کرنا چاہتا ہے۔
اس آرٹیکل میں، ہم ابتدا کرنے والوں سے متعلق ہر چیز کا احاطہ کریں گے، بشمول:
کسٹم کی وضاحت کرتے ہوئے ڈھانچے کے ممبر وائز انیشیلائزر کو کیسے برقرار رکھا جائے۔
کلاسوں میں ابتدائی لکھنا ہمیشہ کیوں ضروری نہیں ہوتا ہے۔
کیوں super.init
کو کال کرنے کی ہمیشہ ایک مقررہ ابتدائی میں ضرورت نہیں ہوتی ہے۔
super.init
کال کرنے سے پہلے ذیلی طبقے کے تمام فیلڈز کو کیوں پاپولیشن کرنا ضروری ہے۔
ذیلی طبقات میں کم سے کم اوور رائیڈ کے ساتھ تمام پیرنٹ انیشیلائزرز تک کیسے رسائی حاصل کی جائے۔
جب بالکل ایک required
ابتداء کی ضرورت ہوتی ہے۔
UIView.init()
کو ہمیشہ پیرامیٹرز کے بغیر کیوں کہا جاتا ہے، لیکن init(frame:)
اور init(coder:)
اوور رائیڈ کیا جاتا ہے
...اور مزید لیکن آئیے اسے قدم بہ قدم چلتے ہیں۔
var
بمقابلہ let
required
ابتدائی کنندہ: generics، protocols، Self()
, final
UIView()
بغیر پیرامیٹرز کےایپل کی گائیڈ دی سوئفٹ پروگرامنگ لینگویج (6) (جو ویسے بھی، ابتدا کرنے والوں کے لیے حیرت انگیز طور پر تفصیلی ہے) کہتی ہے:
ابتداء ایک کلاس، ڈھانچے، یا استعمال کے لیے شمار کی مثال تیار کرنے کا عمل ہے۔ اس عمل میں اس مثال پر ہر ذخیرہ شدہ پراپرٹی کے لیے ایک ابتدائی قدر کا تعین کرنا اور کسی دوسرے سیٹ اپ یا ابتداء کو انجام دینا شامل ہے جو نئی مثال کے استعمال کے لیے تیار ہونے سے پہلے درکار ہے۔
آپ ابتداء کے اس عمل کو شروع کرنے والے کی وضاحت کرتے ہوئے لاگو کرتے ہیں، جو کہ خاص طریقوں کی طرح ہیں جنہیں کسی خاص قسم کی نئی مثال بنانے کے لیے کہا جا سکتا ہے۔ Objective-C انیشیلائزرز کے برعکس، سوئفٹ انیشیلائزرز کوئی قدر واپس نہیں کرتے ہیں۔ ان کا بنیادی کردار یہ یقینی بنانا ہے کہ کسی قسم کی نئی مثالیں پہلی بار استعمال ہونے سے پہلے صحیح طریقے سے شروع کی جائیں۔
ٹھیک ہے، مجھے لگتا ہے کہ مجھے یہاں کچھ بھی شامل کرنے کی ضرورت نہیں ہے۔
آئیے سٹرکچر انیشیلائزرز پر بحث کرتے ہوئے شروع کریں۔ یہ بہت آسان ہے کیونکہ کوئی وراثت نہیں ہے، لیکن پھر بھی کچھ اصول ہیں جن کے بارے میں آپ کو جاننا چاہیے۔
آئیے ایک سادہ ساخت لکھتے ہیں:
struct BankAccount { let amount: Double let isBlocked: Bool } let bankAccount = BankAccount(amount: 735, isBlocked: Bool)
نوٹ کریں کہ ہم واضح طور پر ابتدائیہ کا اعلان کیے بغیر ساخت کو شروع کرنے کے قابل تھے۔ ایسا اس لیے ہوتا ہے کیونکہ ڈھانچے کو کمپائلر کے ذریعے تیار کردہ ممبر وار انیشیلائزر ملتا ہے۔ یہ صرف ڈھانچے کے لیے کام کرتا ہے۔
Refactor → Generate memberwise ابتداء کو منتخب کرکے، آپ دیکھ سکتے ہیں کہ یہ کیسا لگتا ہے:
init(amount: Double, isBlocked: Bool) { self.amount = amount self.isBlocked = isBlocked }
دستخط سے، یہ دیکھنا آسان ہے کہ تمام پیرامیٹرز کے لیے اقدار فراہم کرنے میں ناکامی کے نتیجے میں تالیف کی غلطی ہو جائے گی:
let bankAccount = BankAccount(amount: 735) // ❌ Missing argument for parameter 'isBlocked' in call
تاہم، اگر آپ مطلوبہ دلائل کی تعداد کو کم کرنا چاہتے ہیں، تو آپ اپنی مرضی کے مطابق ابتدا کرنے والے کی وضاحت کر سکتے ہیں:
init(amount: Double, isBlocked: Bool = false) { self.amount = amount isBlocked = isBlocked } let bankAccount = BankAccount(amount: 735) // ✅
نوٹ کریں کہ اگر isBlocked
آباد نہیں کیا گیا ہے، تو اس کے نتیجے میں تالیف کی خرابی ہو گی کیونکہ تمام ڈھانچے کی خصوصیات کو انیشیلائزر میں آباد کرنا ضروری ہے ۔
var
بمقابلہ let
واحد صورت جہاں کسی فیلڈ کو واضح طور پر آباد کرنے کی ضرورت نہیں ہے جب یہ اختیاری ( ?
) متغیر ( var
) ہو۔ ایسی صورتوں میں، فیلڈ ڈیفالٹ ہو جائے گا nil
:
struct BankAccount { let amount: Double var isBlocked: Bool? init(amount: Double) { self.amount = amount } } let bankAccount = BankAccount(amount: 735) // ✅
تاہم، اگر ہم اس معاملے میں ممبر وائز انیشیلائزر کو استعمال کرنے کی کوشش کرتے ہیں، تو ہمیں ایک تالیف کی خرابی ملے گی:
let bankAccount = BankAccount( amount: 735, isBlocked: false ) // ❌ Extra argument 'isBlocked' in call
ایسا اس لیے ہوتا ہے کہ کسٹم انیشیلائزر کا اعلان کرنے سے ممبر وائز انیشیلائزر ہٹ جاتا ہے۔ واضح طور پر اس کی وضاحت کرنا اب بھی ممکن ہے، لیکن یہ خود بخود دستیاب نہیں ہوگا۔
تاہم، ممبر وائز انیشیلائزر کو برقرار رکھنے کے لیے ایک چھوٹی سی چال ہے: extension
میں کسٹم انیشیلائزر کا اعلان کریں۔
struct BankAccount { let amount: Double var isBlocked: Bool? } extension BankAccount { init(amount: Double) { self.amount = amount } } let barclaysBankAccount = BankAccount(amount: 735) // ✅ let revolutBankAccount = BankAccount(amount: 812, isBlocked: false) // ✅ print(barclaysBankAccount.isBlocked) // nil print(barclaysBankAccount.isBlocked) // false
ڈھانچے کا خلاصہ
var
فیلڈز ڈیفالٹ سے nil
extension
میں اپنی مرضی کے مطابق کی وضاحت کریں۔کلاس کے لیے پرائمری انیشیلائزر نامزد انیشیلائزر ہے۔ یہ دو مقاصد کو پورا کرتا ہے:
class Animal { var name: String init(name: String) { self.name = name } } class Dog: Animal { var breed: String var name: String init(breed: String, name: String) { self.breed = breed super.init(name: name) } }
super.init
کال کرنے سے پہلے تمام فیلڈز کو آباد کرنا ضروری ہے ۔ اس کی وجہ یہ ہے کہ سپر کلاس انیشیلائزر ذیلی طبقے کے ذریعے اوور رائیڈ کردہ طریقوں کو کال کر سکتا ہے، جو غیر آباد ذیلی طبقے کی خصوصیات تک رسائی حاصل کر سکتے ہیں۔
class Animal { var age: Int init(age: Int) { self.age = age getInfo() } func getInfo() { print("Age: ", age) } } class Dog: Animal { var breed: String init(breed: String, age: Int) { self.breed = breed // imagine we haven't done this super.init(age: age) } override func getInfo() { print("Age: ", age, ", breed: ", breed) } }
اس طرح، اگر ہم نے self.breed = breed
سیٹ نہ کیا ہوتا تو ہمیں رن ٹائم غلطی کا سامنا کرنا پڑتا کیونکہ Animal
انیشیلائزر نے Dog
کلاس سے اوور رائیڈڈ getInfo()
طریقہ کو کال کیا ہوتا۔ یہ طریقہ breed
جائیداد تک رسائی حاصل کرنے کی کوشش کرتا ہے، جو ابھی تک آباد نہیں ہوگی۔
ڈھانچے کے برعکس، کلاسوں کو رکنیت کے لحاظ سے ایک مضمر ابتدائیہ موصول نہیں ہوتا ہے۔ اگر غیر شروع شدہ خصوصیات ہیں تو، ایک تالیف کی خرابی واقع ہوتی ہے:
class Animal { // ❌ Class 'Animal' has no initializers var age: Int }
class Animal { // ✅ var age: Int = 0 }
class Animal { // ✅ var age: Int? }
class Animal { } // ✅
کلاسوں میں سہولت شروع کرنے والا بھی ہو سکتا ہے۔ نامزد انیشیلائزرز کے برعکس، وہ شروع سے کوئی چیز نہیں بناتے ہیں بلکہ دوسرے انیشیلائزرز کی منطق کو دوبارہ استعمال کر کے ابتدا کے عمل کو آسان بناتے ہیں۔
class Rectangle { var width: Double var height: Double init(width: Double, height: Double) { self.width = width self.height = height } convenience init(side: Double) { self.init(width: side, height: side) // uses a designated initializer of self } }
سہولت شروع کرنے والے یا تو نامزد انیشیلائزرز یا دیگر سہولت انیشیلائزرز کو کال کر سکتے ہیں۔ بالآخر، ایک نامزد ابتدائی کنندہ کو ہمیشہ بلایا جائے گا۔
سہولت شروع کرنے والے ہمیشہ افقی (self.init) جاتے ہیں، اور نامزد ابتدائی عمودی (super.init) جاتے ہیں۔
جیسے ہی کوئی ذیلی طبقہ نئی خصوصیات کا اعلان کرتا ہے، یہ سپرکلاس کے تمام سہولتوں کے آغاز تک رسائی کھو دیتا ہے۔
class Animal { var age: Int var name: String init(age: Int, name: String) { self.age = age self.name = name } convenience init(age: Int) { self.init(age: age, name: "Default") } convenience init(name: String) { self.init(age: 0, name: name) } } class Dog: Animal { var breed: String init(age: Int, name: String, breed: String) { self.breed = breed super.init(age: age, name: name) } } let dog = Dog(age: 3) // ❌ Missing arguments for parameters 'breed', 'name' in call
اسے سپر کلاس کے تمام نامزد ابتدائیوں کو اوور رائیڈ کر کے ٹھیک کیا جا سکتا ہے۔
class Dog: Animal { // ... override init(age: Int, name: String) { self.breed = "Mixed" super.init(age: age, name: name) } } let dog = Dog(age: 3) // ✅
یہ دیکھنا آسان ہے کہ، اس طرح، اگلے ذیلی طبقے میں ایک سہولت انیشیئلائزر استعمال کرنے کے لیے، آپ کو دو انیشیلائزرز کو اوور رائڈ کرنے کی ضرورت ہے۔
class GuideDog: Dog { var isTrained: Bool override init(age: Int, name: String) { self.isTrained = false super.init(age: age, name: name) } override init(age: Int, name: String, breed: String) { self.isTrained = false super.init(age: age, name: name, breed: breed) } init(age: Int, name: String, breed: String, isTrained: Bool) { self.isTrained = isTrained super.init(age: age, name: name, breed: breed) } } let dog = GuideDog(age: 3) // ✅
تاہم، سہولت اوور رائیڈ انیشیلائزر کا استعمال کر کے اس سے بچا جا سکتا ہے۔
class Dog: Animal { var breed: String convenience override init(age: Int, name: String) { self.init(age: age, name: name, breed: "Mixed") // self, not super } init(age: Int, name: String, breed: String) { self.breed = breed super.init(age: age, name: name) } } class GuideDog: Dog { var isTrained: Bool // override init(age: Int, name: String) { // self.isTrained = false // // super.init(age: age, name: name, breed: "Mixed") // } convenience override init(age: Int, name: String, breed: String) { self.init(age: age, name: name, breed: breed, isTrained: false) // self, not super } init(age: Int, name: String, breed: String, isTrained: Bool) { self.isTrained = isTrained super.init(age: age, name: name, breed: breed) } } let dog = GuideDog(age: 3) // ✅
اب ہمارے پاس ہر ذیلی طبقے میں صرف 2 واضح طور پر مخصوص ابتدائیہ ہیں۔
غور کریں کہ کس طرح سہولت کو اوور رائیڈ انیشیلائزر super.init
کی بجائے self
نامزد init کہتے ہیں۔
اس چال کی وضاحت سوئفٹ ان ڈیپتھ کے باب 5 میں Tjeerd کی طرف سے 't Veen میں کی گئی ہے، ایک کتاب جس کی میں انتہائی سفارش کرتا ہوں۔
super.init()
کو کال کرتا ہے۔ہم پہلے ہی بحث کر چکے ہیں کہ اگر ذیلی طبقہ نئے پیرامیٹرز کو متعارف نہیں کرواتا ہے، تو یہ خود بخود سپر کلاس کے تمام ابتدائیوں کو وراثت میں لے جاتا ہے۔
class Base { let value: Int init() { value = 0 } init(value: Int) { self.value = value } } class Subclass: Base { } let subclass = Subclass() // ✅ let subclass = Subclass(value: 3) // ✅
تاہم، ایک اور اہم نکتہ ہے: اگر سپرکلاس میں صرف ایک نامزد ابتدائیہ ہے اور یہ پیرامیٹر لیس ہے ( init()
بغیر دلائل کے، تو پھر ذیلی کلاس میں واضح طور پر اعلان کردہ ابتدا کاروں کو super.init()
کو کال کرنے کی ضرورت نہیں ہے۔ اس صورت میں، سوئفٹ کمپائلر بغیر کسی دلیل کے دستیاب super.init()
پر کال داخل کرتا ہے ۔
class Base { init() { } } class Subclass: Base { let secondValue: Int init(secondValue: Int) { self.secondValue = secondValue // ✅ without explicit super.init() } }
کوڈ مرتب کرتا ہے کیونکہ super.init()
واضح طور پر کہا جاتا ہے۔ یہ مندرجہ ذیل مثالوں میں سے کچھ کے لیے اہم ہے۔
ایک required
انیشیلائزر ان تمام صورتوں میں استعمال کیا جاتا ہے جہاں ایک ذیلی کلاس میں بیس کلاس کی طرح ایک ہی انیشیلائزر ہونا ضروری ہے۔ اسے super.init()
کو بھی کال کرنا چاہیے۔ ذیل میں ایسی مثالیں دی گئی ہیں جہاں ایک required
ابتداء ضروری ہے۔
ایک عام قسم پر init
کال کرنا صرف اسے ایک required init
قرار دے کر ہی ممکن ہے۔
class Base { } class Subclass: Base { } struct Factory<T: Base> { func initInstance() -> T { // ❌ Constructing an object of class T() // type 'T' with a metatype value } // must use a 'required' initializer }
یہ کوڈ مرتب نہیں ہوتا ہے کیونکہ Factory
Base
کے ذیلی طبقات کے بارے میں کچھ نہیں معلوم۔ اگرچہ اس خاص معاملے میں، Subclass
میں پیرامیٹرز کے بغیر ایک init()
ہے، تصور کریں کہ کیا اس نے ایک نیا فیلڈ متعارف کرایا ہے:
class Subclass: Base { let value: Int init(value: Int) { self.value = value } }
یہاں، اس میں اب کوئی خالی init
نہیں ہے، لہذا اسے required
کے مطابق قرار دیا جانا چاہیے۔
class Base { required init() { } } class Subclass: Base { } struct Factory<T: Base> { static func initInstance() -> T { // ✅ T() } } let subclass = Factory<Subclass>.initInstance()
نوٹ کریں کہ اگرچہ ہم نے واضح طور پر Subclass
میں required init
اعلان نہیں کیا، لیکن مرتب کرنے والے نے اسے ہمارے لیے تیار کیا۔ اس پر کمپائلر اسسٹنس میں تبادلہ خیال کیا گیا تھا۔ required init
خود بخود وراثت میں ملا تھا اور اسے super.init()
کہا جاتا تھا۔
class Subclass: Base { required init() { super.init() } }
پروٹوکول میں اعلان کردہ تمام ابتداء کی required
:
protocol Initable { init() } class InitableObject: Initable { init() { // ❌ Initializer requirement 'init()' can only // be satisfied by a 'required' initializer } // in non-final class 'InitableObject' }
ایک بار پھر، یہ ضروری ہے تاکہ کمپائلر اس بات کو یقینی بنائے کہ ذیلی کلاس پروٹوکول انیشیلائزر کو لاگو کرتا ہے۔ جیسا کہ ہم پہلے ہی جانتے ہیں، ایسا ہمیشہ نہیں ہوتا — اگر init
required
نہیں ہے، ذیلی طبقے کو اس کو اوور رائڈ کرنے کا پابند نہیں ہے اور وہ خود اپنے ابتدائی کنندہ کی وضاحت کر سکتا ہے۔
class IntValue: InitableObject { let value: Int init(value: Int) { self.value = value } } let InitableType: Initable.Type = IntValue.self let initable: Initable = InitableType.init()
یقینا، درج ذیل کوڈ مرتب نہیں ہوگا کیونکہ Base.init()
required
نہیں ہے۔
class InitableObject: Initable { required init() { } // ✅ } class IntValue: InitableObject { let value: Int required init() { self.value = 0 } init(value: Int) { self.value = value } }
اسی طرح کی صورتحال اس وقت ہوتی ہے جب Self()
انیشیلائزر کو جامد طریقوں میں کال کرتے ہیں۔
class Base { let value: Int init(value: Int) { self.value = value } static func instantiate() -> Self { Self(value: 3) // ❌ Constructing an object of class type 'Self' } // with a metatype value must use a 'required' initializer }
ہمیشہ کی طرح، مسئلہ وراثت میں ہے:
class Subclass: BaseClass { let anotherValue: Int init(anotherValue: Int) { self.anotherValue = anotherValue } } let subclass = Subclass.instantiate() // ❌
class BaseClass { let value: Int required init(value: Int) { // ✅ self.value = value } static func instantiate() -> Self { Self(value: 3) } }
required
سے چھٹکارا حاصل کرنا: final
چونکہ required
کا مقصد ذیلی طبقات میں ابتدائیہ کے نفاذ کو نافذ کرنا ہے، قدرتی طور پر، final
مطلوبہ لفظ کا استعمال کرتے ہوئے وراثت پر پابندی لگانا required
کے مطابق ابتدائیہ کو نشان زد کرنے کی ضرورت کو ختم کرتا ہے۔
protocol Initable { init() } final class InitableObject: Initable { } // ✅
protocol ValueInitable { init(value: Int) } final class ValueInitableObject: ValueInitable { init(value: Int) { } // ✅ }
init()
پیرامیٹرز کے بغیر ہے، تو اسے سب کلاس انیشیلائزرز میں خود بخود کہا جاتا ہے۔Self()
میں استعمال کے لیے ذیلی طبقات میں اس کی موجودگی کی ضمانت کے لیے ایک required
ابتداء کار کی ضرورت ہے۔ پیرامیٹرز کے بغیر UIView()
انیشیلائزر کا مختصر تذکرہ، جو دستاویزات میں نہیں پایا جا سکتا لیکن ہر جگہ پراسرار طور پر استعمال ہوتا ہے۔
وجہ یہ ہے کہ UIView
NSObject
سے وراثت میں ملتا ہے، جس میں init()
پیرامیٹرز کے بغیر ہوتا ہے۔ لہذا ، اس ابتداء کار کو UIView
انٹرفیس میں واضح طور پر اعلان نہیں کیا گیا ہے، پھر بھی یہ دستیاب ہے:
@available(iOS 2.0, *) @MainActor open class UIView : UIResponder, NSCoding, UIAppearance, UIAppearanceContainer, UIDynamicItem, UITraitEnvironment, UICoordinateSpace, UIFocusItem, UIFocusItemContainer, CALayerDelegate { open class var layerClass: AnyClass { get } public init(frame: CGRect) public init?(coder: NSCoder) open var isUserInteractionEnabled: Bool // no init()
تاہم، ہڈ کے نیچے، یہ انیشیلائزر init(frame:)
کہتا ہے جب کوڈ میں شروع کیا جاتا ہے یا init(coder:)
جب انٹرفیس بلڈر کے ذریعے شروع کیا جاتا ہے۔ ایسا اس لیے ہوتا ہے کیونکہ UIView
NSObject.init()
کا اپنا نفاذ فراہم کرتا ہے، جس کی تصدیق اس حقیقت سے کی جا سکتی ہے کہ method_getImplementation
NSObject.init()
اور UIView.init()
کے لیے مختلف پتے واپس کرتا ہے۔
ایک ناکام init صرف ایک ہے جو اختیاری لوٹاتا ہے۔
final class Failable { let positiveValue: Int init?(value: Int) { guard value > 0 else { return nil } positiveValue = value } }
خام قیمت والے اینومس کو مفت init?(rawValue:)
enum Direction: String { case north case west case south case east } let north = Direction(rawValue: "north")
آپ enums کے لیے اپنی مرضی کے مطابق init بھی بنا سکتے ہیں۔ تمام enum inits کو self
تفویض کرنا ضروری ہے۔
enum DeviceType { case phone case tablet init(screenWidth: Int) { self = screenWidth > 800 ? .tablet : .phone } }
ہم نے Swift میں ابتدائیہ کے تمام ضروری پہلوؤں کا احاطہ کیا ہے:
انیشیلائزر میں، تمام فیلڈز کو پاپولڈ ہونا چاہیے۔
اختیاری var
پراپرٹیز ڈیفالٹ سے nil
۔
سٹرکچرز کو ایک مفت ممبر وائز انیشیلائزر ملتا ہے۔
ممبر وائز انیشیلائزر غائب ہو جاتا ہے جب ایک کسٹم انیشیلائزر کی تعریف کی جاتی ہے۔
ایک نامزد انیشیلائزر یقینی بناتا ہے کہ تمام فیلڈز آباد ہیں اور super.init()
کو کال کرتا ہے۔
ایک سہولت انیشیلائزر ایک نامزد انیشیلائزر کو کال کرکے ابتدا کو آسان بناتا ہے۔
سہولت شروع کرنے والے ہمیشہ افقی ہوتے ہیں ( self.init
)، اور نامزد انیشیلائزر عمودی ہوتے ہیں ( super.init
)۔
ایک سہولت شروع کرنے والا ذیلی طبقات کے لیے دستیاب نہیں ہو جاتا ہے اگر وہ نئی خصوصیات کا اعلان کرتے ہیں۔
ایک سپر کلاس کے سہولت انیشیلائزر کو بحال کرنے کے لیے، اس کے تمام نامزد کردہ انیشیلائزرز کو اوور رائڈ کرنا ضروری ہے۔
اوور رائیڈز کی تعداد کو کم کرنے کے لیے، سہولت اوور رائیڈ انیشیلائزر استعمال کیا جا سکتا ہے۔
اگر ایک ذیلی کلاس نئے پیرامیٹرز کو متعارف نہیں کراتی ہے، تو یہ خود بخود اپنے سپرکلاس سے تمام ابتداء کو وراثت میں لے لیتا ہے۔
اگر سپر کلاس میں صرف init()
پیرامیٹرز کے بغیر ہے، تو اسے خود بخود ذیلی کلاس انیشیلائزرز میں بلایا جاتا ہے۔
ایک مطلوبہ انیشیئلائزر generics، protocols، اور Self()
میں استعمال کے لیے ذیلی طبقات میں اپنی موجودگی کو یقینی بناتا ہے۔
UIView.init()
UIView.init(frame:)
یا UIView.init(coder:)
کال کرتا ہے۔
ایک ناکام شروع کرنے والا ایک اختیاری واپس کرتا ہے۔
خام قدر والے اینومس کو مفت init?(rawValue:)
۔
تمام enum ابتداء کرنے والوں کو self
تفویض کرنا ہوگا۔
مجھے امید ہے کہ آپ نے اس مضمون میں کچھ مفید پایا۔ اگر کوئی چیز غیر واضح رہتی ہے یا آپ کو غلط معلوم ہوتا ہے، تو ٹیلیگرام پر مفت وضاحت کے لیے بلا جھجھک مجھ سے رابطہ کریں: @kfamyn ۔