<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های Pouya Yarandi</title>
        <link>https://virgool.io/feed/@p.yarandi</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-06-18 05:35:33</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/77659/avatar/WGCthj.png?height=120&amp;width=120</url>
            <title>Pouya Yarandi</title>
            <link>https://virgool.io/@p.yarandi</link>
        </image>

                    <item>
                <title>توابع Higher Order برای آرایه‌ها در سوییفت</title>
                <link>https://virgool.io/@p.yarandi/%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-higher-order-%D8%A8%D8%B1%D8%A7%DB%8C-%D8%A2%D8%B1%D8%A7%DB%8C%D9%87%D9%87%D8%A7-%D8%AF%D8%B1-%D8%B3%D9%88%DB%8C%DB%8C%D9%81%D8%AA-woj4jtqp45cq</link>
                <description>سلام. من دوباره با یه مقاله سوییفتی دیگه اومدم. تو این مقاله میخوام راجع به Higher Order Function ها در سوییفت صحبت کنم. بذارید تو شروع صحبتم بگم که اصلا Higher Order Function چیه. به طور کلی تابعی که ورودی یا خروجیش یه تابع دیگه باشه بهش میگن Higher Order Function. بعضی از این توابع، توابعی هستن که روی آرایه ها اعمال میشن. ما توی این مقاله میخوایم به چندتا از توابع Higher Order برای آرایه های سوییفتی بپردازیم. توابعی که ما میخوایم بررسیشون کنیم توابع زیر هستن: تابع sorted: برای مرتب سازی آرایهتابع filter: برای جستجو توی آرایهتابع map: برای نگاشت عنصرهای آرایهتابع compactMap: اینم برای نگاشت عناصره ولی با یه تفاوت کوچک که توضیح میدمتابع reduce: برای اعمال محاسبه روی عناصر آرایه و در نهایت برگشت یه مقدار به ازای کل عناصراینم بگم که اگه هر کدوم از این توابع رو توی ایکس کد ببینید متوجه میشید که ورودیشون یه closure هست و به این دلیل جزو Higher Order ها محسوب میشن. خب موافقین بریم سراغ اولین تابع؟تابع sortedاین تابع برای مرتب سازی آرایه استفاده میشه. فرض کنید یه آرایه از اعداد داریم و میخوایم اونو به صورت صعودی و نزولی مرتب کنیم. من این کارو برای هر کدوم از این مرتب سازی ها با یه سینتکس انجام میدم تا شما انواع تعریف closure برای این تابع رو ببینید:let unsortedArray = [20, 5, 26, 40, 30, 50, 19]
let sortedArrayAsc = unsortedArray.sorted { (first, second) -&gt; Bool in
    return first &lt; second
}
// [5, 19, 20, 26, 30, 40, 50]خب همونطور که میبینید من برای ورودی تابع مرتب سازی از یه closure استفاده کردم که ورودیش دوتا مقدار از نوع داده عناصر آرایه مون هست و خروجی هم از جنس Bool یا همون بولینه. توی این closure ما در واقع تعریف میکنیم که به ازای چه مقادیری از هر دو عنصر (در مقایسه با هم) مقدار true برمیگرده. توی همین مثال ما گفتیم در شرایطی مقدار ture برمیگرده که عنصر اول از دوم کوچیکتر باشه. در نتیجه آرایه ما به صورت صعودی مرتب میشه یعنی به ازای هر دو عنصری که در نظر بگیرین اولی کوچیکتر از دومی هست.برای تابع مرتب سازی میشه به یه شکل دیگه هم closure رو معرفی کرد که شاید یکم خوانایی پایینتری داشته باشه اما کوتاهتره و کدنویسی کمتری داره و اونم به شکل زیره:let sortedArrayDesc = unsortedArray.sorted(by: { $0 &gt; $1 })
// [50, 40, 30, 26, 20, 19, 5]اگه دقت کنید closure من خیلی کوچیکتر شد. اول اینکه دیگه لازم نیست آرگومان های closure رو تعریف کنم. دوم اینکه لازم نیست چیزی return شه و فقط کافیه statement لازم رو  بنویسید. به جای آرگومان ها هم از $ و شماره آرگومان استفاده میکنین. توی خط کد بالا من آرایه ای که بالاتر تعریف کرده بودم به صورت نزولی مرتب کردم.تابع filterاین تابع کارش اینه که توی آرایه ما بر اساس شرطی که تعریف میکنیم بین عناصر آرایه جستجو کنه. چیزایی که در مورد تابع sorted گفتم برای این تابع و بقیه توابعم صادقه و اصول تعریف closure توی همه این توابع یکسانه. برای مثال من میخوام یه آرایه از مختصات (دوتایی های x و y) تعریف کنم و توی اون دوتا فیلتر اعمال کنم. یکی مختصات با y کمتر از ۱۶ و یکی مختصات با x کمتر از ۱۰:let targetArray = [
    (x: 10, y: 20),
    (x: 5, y: 8),
    (x: 7, y: 15),
    (x: 12, y: 31),
    (x: 3, y: 4)
]

let pointsWithYLessThan16 = targetArray.filter { (tuple) -&gt; Bool in
    return tuple.y &lt; 16
}
// [(x: 5, y: 8), (x: 7, y: 15), (x: 3, y: 4)]

let pointsWithXGreaterThan10 = targetArray.filter({ $0.x &gt; 10 })
// [(x: 12, y: 31)]تابع mapاین تابع عملکردش اینه که بر اساس مقدار بازگشتی توی closure همه عناصر آرایه رو به یک مقدار دیگه نگاشت میکنه. دیگه صحبتای تکراری که توی دوتا بخش قبلی انجام دادم تکرار نمیکنم فقط بدونید که همون شیوه های تعریف closure رو داریم. برای دیدن عملکرد این تابع من میخوام از همون آرایه مثال قبل استفاده کنم. فرض کنید آرایه ای از مختصات دارم و میخوام مقدار هر کدوم اونارو به فاصله اقلیدسی و فاصله منهتن اونها از مبدا مختصات (نقطه با مختصات صفر) نگاشت کنم. اینکه فاصله اقلیدسی و منهتن چیه بماند؛ چون موضوع بحث ما نیست. فقط همینقدر بگم که فاصله اقلیدسی جذر جمع توان دوی x و y هست و فاصله ی منهتن هم از جمع x و y نقطه بدست میاد:let euclideanDistances = targetArray.map { (tuple) -&gt; Double in
    return sqrt(pow(Double(tuple.x), 2) + pow(Double(tuple.y), 2))
}
// [22.360679774997898, 9.433981132056603, 16.55294535724685, 33.24154027718932, 5.0]

let manhattanDistances = targetArray.map { $0.x + $0.y }
// [30, 13, 22, 43, 7]یه نکته ریزم همینجا بگم در مورد شکل اختصاری تعریف closure اونم اینکه اگه قرار نیست خود تابع Higher Order که از اون استفاده میکنید توسط تابع دیگه ای فراخوانی بشه میتونید پرانتزهای دور closure رو نذارید. دقیقا مثل مثال بالا.تابع compactMapاین تابعم دقیقا مثل تابع map عمل نگاشت عناصر رو انجام میده. منتها با این تفاوت که اگر تو این نگاشت عنصری nil شد اونو توی آرایه بازگشتی نمیاره. برای مثال فرض کنید من آرایه ای از String دارم میخوام عناصر اون رو نگاشت کنم به URL. و از اونجایی که init یک شی از جنس URL به وسیله String برای من یک URL آپشنال میسازه (یعنی ممکنه مقدارش nil باشه) از تابع compactMap به جای map استفاده میکنم:let websites = [
    &amp;quothttps://google.com&amp;quot,
    &amp;quotit&#039;s not an address!&amp;quot,
    &amp;quothttps://apple.com&amp;quot
]

let validUrls = websites.compactMap { URL(string: $0) }
// [https://google.com, https://apple.com]تابع reduceوظیفه این تابع اینه که با استفاده از closure تعریف شده میاد یه محاسبه کلی رو روی همه عناصر از اول تا اخر انجام میده و نهایتا یه result برمیگردونه. بذارید با یه مثال همه چیز رو روشن تر کنم. فرض کنید یه آرایه از بولین ها داریم و میخوایم ببینیم که and همه اونا true میشه یا نه. گرچه برای چنین کاری راه های دیگه هم هست ولی من چون میخوام از reduce استفاده کنم باید بیام بگم همه عناصر رو با هم and کن و در نهایت نتیجه رو برگردون. این کارو این طوری انجام میدم:let someBooleans = [true, false, true, true]
let isAllTrue1 = someBooleans.reduce(true) { (result, item) -&gt; Bool in
    return result &amp;&amp; item
}
// falseتوی این تابع تعریف closure یه مقدار از باقی توابع متفاوته. اینجا ما یه result و یه item داریم که به ترتیب بیانگر مقدار بدست آمده از اعمال محاسبات روی عناصر قبلی و عنصر فعلی هستن. و مقدار برگشتی روی عنصر بعدی اعمال میشه تا آخر که به عنوان خروجی تابع ما return میشه. علاوه بر این، تابع reduce یه آرگومان دیگه هم به جز closure داره که اونم مقدار اولیه result هست. یعنی result ما قبل از اعمال محاسبات روی عنصر صفرم آرایه رو مشخص میکنه.ولی اگه توی ایکس کد reduce رو بنویسید متوجه میشید که دو نوع ورودی میتونه بگیره این تابع. تفاوت این دوتا چیه به نظرتون. الان براتون میگم. توی نوع بالا result یه آرگومانه و همونطور که احتمالا میدونید آرگومان های closure ها به طور پیشفرض ثابت هستن. یعنی مقدارشون قابل تغییر نیست. برای همینم میبینید که حتما باید نتیجه محاسبه return بشه که حالا توی مثال ما خروجی Bool بود ولی هر نوع داده دیگه ای هم میتونه باشه. اما توی مثال پایین که یه جورایی بازنویسی همون بالایی هست میبینید که آرگومان result از نوع inout تعریف شده و در نتیجه امکان تغییر مقدار اون رو داریم. برای همین میبینید که توی مثال پایین نیازی به return کردن مقدار نداریم چون مستقیما تغییرات رو روی result اعمال میکنیم:let allTrueBools = [true, true, true, true]
let isAllTrue2 = allTrueBools.reduce(into: true) { (result, item) in
    result = result &amp;&amp; item
}
// trueاستفاده ترکیبی از توابع Higher Orderشما میتونید به صورت ترکیبی هم از توابعی که بالا معرفی کردیم استفاده کنید. مثلا تابع زیر میاد عناصر بزرگتر از 20 رو به صورت مرتب شده برمیگردونه:let unsortedArray = [20, 5, 26, 40, 30, 50, 19]
let sortedGreaterThan20 = unsortedArray
    .filter({ $0 &gt; 20 })
    .sorted(by: { $0 &lt; $1 })
    
// [26, 30, 40, 50]تمرینخب برای اینکه مطمئن شید که خوب یاد گرفتین دو تا تمرین زیر رو توی ایکس کد بزنید و بعد با جواب چک کنید کد خودتون رو.// array for question 1
let addresses = [
    &amp;quothttps://mail.google.com&amp;quot, 
    &amp;quotit&#039;s not an address!&amp;quot,
    &amp;quothttps://apple.com&amp;quot,
    &amp;quotjust a fake address which is sooo long&amp;quot
]

// array for question 2
let values = [&amp;quotPouya&amp;quot, &amp;quot40&amp;quot, &amp;quot67&amp;quot, &amp;quotPayam&amp;quot, &amp;quot93&amp;quot, &amp;quotNima&amp;quot, &amp;quot21&amp;quot, &amp;quot74&amp;quot, &amp;quot!&amp;quot, &amp;quot36&amp;quot]از بین آدرس های موجود در آرایه رشته های زیر بزرگترین آدرس URL معتبر (آدرسی که قابل نگاشت به URL باشد) را پیدا کنید. در صورتی که هیچ آدرس معتبری وجود نداشت عبارت No valid address رو توی کنسول چاپ کنید. (راهنمایی: برای پیدا کردن بزرگترین کافیه آرایه رو نزولی مرتب کنید و عنصر اول رو با مشخصه first از آرایه برگردونید.)مجموع مقادیری را بیابید که اولا عددی هستن و ثانیا بزرگتر از ۵۰ باشن.سعی کنید خودتون و بدون دیدن جواب کد سوالات بالا رو بزنید و بعدش جوابارو چک کنید. میتونیدم بعد از اینکه تلاشتون رو کردین کدای پایین رو توی ایکس کدتون کپی کنید و نتیجه ش رو ببینید.پاسخ تمرینات// answer 1
let longestValidAddress = addresses
    .compactMap({ URL(string: $0) })
    .map({ $0.absoluteString })
    .sorted(by: { $0.count &gt; $1.count })
    .first
    
print(longestValidAddress ?? &amp;quotNo valid address&amp;quot)

// answer 2
let sumOfNumericsGreaterThan50 = values
    .compactMap({ Int($0) })
    .filter({ $0 &gt; 50 })
    .reduce(0) { (result, item) -&gt; Int in
        return result + item
    }
    
print(sumOfNumericsGreaterThan50)نتیجه گیریتوی این مقاله با چند تا از Higher Order Function های پرطرفدار زبان سوییفت آشنا شدیم و نحوه نوشتن closure برای هر کدوم از اونا رو به شکل فرمال و اختصاری با هم دیدیم. خوندن این مقاله میتونه کمک کنه تا از این به بعد هم محاسبات روی آرایه ها رو در سوییفت با کدهای تمیزتر و کوتاه تری انجام بدید و هم درک خوبی از ساختار closure ها و توابع Higher Order داشته باشید. امیدوارم این مقاله براتون مفید باشه و مثل همیشه لایک فراموش نشه لطفا :)</description>
                <category>Pouya Yarandi</category>
                <author>Pouya Yarandi</author>
                <pubDate>Wed, 25 Dec 2019 01:50:36 +0330</pubDate>
            </item>
                    <item>
                <title>ویژگی Operator Overloading در سوییفت</title>
                <link>https://virgool.io/@p.yarandi/%D9%88%DB%8C%DA%98%DA%AF%DB%8C-operator-overloading-%D8%AF%D8%B1-%D8%B3%D9%88%DB%8C%DB%8C%D9%81%D8%AA-kpsvrwh0brjx</link>
                <description>سلام من برگشتم! خب امروز میخوام راجع به یه مفهوم صحبت کنم به نام Operator Overloading. و از اونجایی که خستمه (?) و برام سخته هر بار بخوام کل کلمه ش رو تایپ کنم از این به بعد میگم oo. ایده این مفهوم اینه که شما میتونید رفتار یک عملگر مثل == رو تغییر بدید. بذارین با یه مثال ساده شروع کنیم:فرض کنید یک کلاس فرد (Person) داریم که شامل کد ملی و نام فرد هست:class Person {
    var name: String
    var nationalCode: String
    
    init(name: String, nationalCode: String) {
        self.name = name
        self.nationalCode = nationalCode
    }
}خب حالا فرض کنید من میخوام عملگر == رو تعریف کنم تا بتونم دوتا شی از کلاس Person رو با هم مقایسه کنم. این کارو اینطوری انجام میدم:extension Person {
    static func == (left: Person, right: Person) -&gt; Bool {
        return left.name == right.name &amp;&amp; left.nationalCode == right.nationalCode
    }
}حالا میتونم از این عملگر واسه اشیا کلاسم استفاده کنم:let person = Person(name: &amp;quotPouya&amp;quot, nationalCode: &amp;quot001&amp;quot)
let samePerson = person
let anotherPerson = Person(name: &amp;quotPayam&amp;quot, nationalCode: &amp;quot002&amp;quot)

print(person == samePerson)
print(person == anotherPerson)

// OUTPUT:
// true
// falseحالا میخوام یه مثال دیگه براتون بزنم تا بیشتر با مفاهیم مرتبط با oo آشنا بشید. همونطور که احتمالا میدونید توی سوییفت عملگر ++ نداریم و من میخوام الان بسازمش. برای اینکار لازمه بدونید که عملگرها میتونن سه حالت داشته باشن:پیشوندی (Prefix): عملگری که قبل از عملوند میاد.میانوندی (Infix): عملگری که بین دوتا عملوند میاد.پسوندی (Postfix): عملگری که بعد از عملوند میاد.عملگر ++ وقتی به صورت پیشوندی باشه اول مقدار متغیر رو زیاد میکنه و بعد مقدارشو برمیگردونه. و وقتی به شکل پسوندی استفاده بشه اول مقدار برمیگرده و بعد زیاد میشه. خب بریم کدش رو با هم ببینیم تا بعدش توضیح بدم چی شدهprefix func ++ &lt;T: Numeric&gt; (right: inout T) -&gt; T {
    right += 1
    return right
}

postfix func ++ &lt;T: Numeric&gt; (left: inout T) -&gt; T {
    let value = left
    left += 1
    return value
}

var counter = 0
counter++
++counterخب همونطور که میبینید من اول اومدم این Overload رو به ازای تمام مقادیر عددی تعریف کردم (یعنی اومدم گفتم جنس عملوند من T هست که بصورت Generic تعریف شده و بعد گفتم که Numeric هست). بعد اومدم گفتم خروجی عملگرمم از همون جنس عملوندم هست. اینم بگم که عملوندم رو به صورت inout تعریف کردم تا امکان تغییر مقدارش رو داشته باشم. پس اینم از مثال عملگرهای پسوندی و پیشوندی. بریم سراغ مثال آخر.توی این مثال میخوام یه کلاس تعریف کنم که بیان کننده گره های لینک لیست هست. هر گره یه دیتا داره که من رشته در نظر گرفتم و یه ارجاع به گره بعدی خودش که منطقا Optional هست چون آخرین گره لیست پیوندی به گره دیگه ای اشاره نمیکنه اگر لیستمون حلقوی نباشه.کلاس گره رو اینطوری تعریف میکنم:class Node {
    var data: String
    weak var link: Node?
    
    init(_ data: String) {
        self.data = data
    }
}خب حالا فرض کنید میخوام یه عملگر تعریف کنم که یه گره رو به یه گره دیگه لینک کنه یعنی مثلا A ~&gt; Bرفتارش اینطوری باشه که گره A به گره B به عنوان گره بعدیش اشاره کنه. برای این کار عملگرم رو اینطوری تعریف میکنم:func ~&gt; (left: Node, right: Node) {
    left.link = right
}خب حالا چندتا گره تعریف میکنم:let node1 = Node(&amp;quotBMW&amp;quot)
let node2 = Node(&amp;quotAudi&amp;quot)
let node3 = Node(&amp;quotVolvo&amp;quot)
let node4 = Node(&amp;quotNissan&amp;quot)
let node5 = Node(&amp;quotHonda&amp;quot)حالا برای لینک کردنشون به هم باید بگم:node1 ~&gt; node2
node2 ~&gt; node3
node3 ~&gt; node4
...موافقین راه حل خوبی نیست و کدنویسی زیادی داره؟ بهتر نمیشد اگه میتونستم تو یه خط چند بار عملگری که تعریف کردم به کار ببرم؟خب باید بگم که برای عملگرهای میانوندی مفهومی هست به نام precedencegroup که کمک میکنه مجموعه ای از عملگرا با هم به کار برن. الان یه precedencegroup تعریف میکنم تا بتونم چند بار عملگرم رو کنار هم استفاده کنم و اولویت اعمال عملگر رو از هم چپ به راست در نظر میگیرم.precedencegroup LinkerOperator {
    associativity: left
}خب حالا عملگرم رو به عنوان عضو این precedencegroup تعریف میکنم:infix operator ~&gt; : LinkerOperatorتا یادم نرفته تابع Overload که بالا نوشته بودم رو هم یه تغییر کوچیک بدم: func ~&gt; (left: Node, right: Node) -&gt; Node {
    left.link = right
    return right
}تنها تغییری که دادم این بود که آخرش که لینک کردم عملوند سمت راست رو برای عملگرای بعدی دوباره return کردم. همین :)تنها کاری که میخوام بکنم اینه که یه تابع بنویسم که لیستم رو پیمایش کنه تا بتونیم نتیجه رو ببینیم:func showLinkList(_ linkList: Node) {
    print(linkList.data)
    if let link = linkList.link {
        showLinkList(link)
    }
}تبریک! حالا دیگه عملگرمون آماده استفاده ست:let starterNode = node1
node1 ~&gt; node2 ~&gt; node3 ~&gt; node4 ~&gt; node5
showLinkList(starterNode)

// OUTPUT:
// BMW
// Audi
// Volvo
// Nissan
// Hondaنتیجه گیریما در مورد مفهوم oo صحبت کردیم و سه تا مثال ازش دیدیم. توی مثال اول بیشتر مفهوم oo رو شناختیم. توی مثال دوم با بررسی انواع عملگر موفق شدیم عملگر ++ رو پیاده سازی کنیم و توی مثال سوم با  precedencegroup برای عملگرهای میانوندی آشنا شدیم. امیدوارم این مقاله کمکتون کرده باشه و اگر کمک کننده بوده لایک فراموش نشه لطفا ☺️?</description>
                <category>Pouya Yarandi</category>
                <author>Pouya Yarandi</author>
                <pubDate>Tue, 10 Dec 2019 22:28:21 +0330</pubDate>
            </item>
                    <item>
                <title>پیاده سازی متدهای Delegate در زبان سوییفت</title>
                <link>https://virgool.io/@p.yarandi/%D9%BE%DB%8C%D8%A7%D8%AF%D9%87-%D8%B3%D8%A7%D8%B2%DB%8C-%D9%85%D8%AA%D8%AF%D9%87%D8%A7%DB%8C-delegate-%D8%AF%D8%B1-%D8%B2%D8%A8%D8%A7%D9%86-%D8%B3%D9%88%DB%8C%DB%8C%D9%81%D8%AA-k9naqnpf41ce</link>
                <description>سلام. اگر تجربه توسعه ی اپلیکیشن داشته باشید احتمالا می‌دونید که یکی از دغدغه های همیشگی توسعه‌دهنده‌ها اینه که بتونن مدیریت رویدادهای مرتبط با هر بخش کد رو انجام بدن. برای مثال ممکنه شما نیاز داشته باشید در هنگام بروز یه رویداد (که جزئیاتش هم دست شما نیست) یک سری فرآیندهایی رو اجرا کنید.گیج‌کننده بود؟ بذارید یه مثال بزنم. فرض کنید از یک کتابخونه استفاده می‌کنید که وظیفه‌ش پخش کردن ویدیو هست. توی این کتابخونه یک متد دارین تحت عنوان ()play که پخش ویدیو رو انجام میده. حالا فکر کنید شما لازم دارین تا در پایان پخش ویدیو یک کاری رو انجام بدین. مثلا یک پیامی رو به کاربر نشون بدین. خب... شما که به کدهای داخل کتابخونه دسترسی ندارین. اصلا حتی اگر هم داشتین دستکاری کردن کدهای یه نفر دیگه قطعا براتون کار جذابی نبود. بود؟اینجا دقیقا همون جاییه که مفهوم متدهای Delegate به کمک ما میاد. البته اگه شما برنامه نویس سوییفت نیستین و با زبان‌ها و تکنولوژی‌های دیگه کار کردین ممکنه اصطلاح دیگه‌ای رو (مثل Listener یا ...) برای این مفهوم به کار ببرین. در نتیجه می‌تونم بگم اگه بخواین بعدا کتابخونه‌ای رو توسعه بدین و اصلا حتی بخواین کد تمیزتر و خواناتری داشته باشین این مفهوم می‌تونه کمکتون کنه. بریم برای پیاده سازی؟تعریف مسئلهمسئله ای که میخوام به عنوان نمونه معرفی کنم یه کلاس خیلی سادست. فرض کنید می‌خوایم یه کلاس شمارنده بسازیم. این کلاس در شروع برای ساخته شدن یه مقدار هدف (goal) از ما میگیره و یه متد Delegate داره که وقتی شمارنده به عدد هدف رسید اجرا می‌شه. خب پس بریم برای ساختن این کلاس خیلی ساده و آموزنده :))برای تعریف Delegate ها از پروتکل‌ها استفاده می‌کنیم. دلیلشم اینه که هر کلاسی می‌تونه از چندین پروتکل پیروی کنه و اینطوری هر کدوم از کنترلرهای ما می‌تونن چندین Delegate رو هندل کنن. خب پس ما اول میایم پروتکل CounterDelegate رو تعریف میکنیم. همونطور که گفتم وظیفه این کلاس تعریف متدهای دلیگیت هستش. من دوتا متد تعریف می‌کنم؛ یکی برای زمانی که مقدار شمارنده تغییر می‌کنه و یکی دیگه برای زمانی که به هدف می‌رسیم.protocol CounterDelegate : class {
    func counter(valueChanged from: Int, to: Int)
    func counter(reachedToGoal goal: Int)
}اینجا من توی تعریف پروتکل (خط ۱) مشخص کردم که فقط کلاس ها میتونن از اون استفاده کنن. دلیلش رو یکم جلوتر میگم. ‌خب حالا می‌خوایم خود کلاس شمارنده رو پیاده سازی کنیم. من کلاسم رو اینطوری تعریف میکنم.class Counter {
    /// مقدار فعلی شمارنده
    private var index: int = 0 
    /// مقدار قبلی شمارنده
    private var lastIndex: int = 0
    /// مقدار هدف
    public var goal: Int
    
    public weak var delegate: CounterDelegate?
    
    init(goal: Int) {
        self.goal = goal
    }
    
    /// کاهش مقدار شمارنده
    func decrease() {
        lastIndex = index
        index -= 1
        callDelegateMethods()
    }
    
    /// افزایش مقدار شمارنده
    func increase() {
        lastIndex = index
        index += 1
        callDelegateMethods()
    }
    
    private func callDelegateMethods() {
    }
}
دقت کنید که متغیر delegate رو از نوع weak تعریف کردم تا از ایجاد strong reference cycle جلوگیری بشه. دلیل اینکه پروتکل دلیگیت رو هم فقط برای کلاس قابل استفاده در نظر گرفتم همین بود. وگرنه کامپایل ارور میگرفتم. برای اینکه بهتر درک کنید که سیکل ارجاع چیه اگه دوست داشتید این مقاله رو بخونید.خب به نظر می‌رسه همه چی عالیه. حالا میخوام تابعی رو تعریف کنیم که بالاتر بدنه ش رو خالی گذاشتم. تابع callDelegateMethods وظیفه ش اینه که بعد از هر کدوم از عملیات اصلی کلاس (یعنی کاهش و افزایش) متدهای دلیگیت رو بر حسب نیاز فراخوانی کنه. من این تابع رو اینطوری تعریف می‌کنم.private func callDelegateMethods() {
    delegate?.counter(valueChanged from: lastIndex, to: index)
    if goal == index {
        delegate?.counter(reachedToGoal goal: index)
    }
}دقت کنید دلیل اینکه پشت متغیر delegate علامت سوال قرار گرفته بخاطر اینه که من بالاتر این متغیر رو آپشنال تعریف کردم. چون زور که نیست شاید اصن یکی دلش نخواد از دلیگیت کلاس من استفاده کنه :))تقریبا دیگه کار تمومه و می‌خوام یه کلاس بسازم که شمارنده استفاده کنه. اسمش رو میذارم MyClass و توش یه آبجکت از Counter می‌سازم. هدف شمارنده رو هم ۲ میذارم.class MyClass {
    let counter = Counter(goal: 2)
    
    init() {
        counter.delegate = self
    }
    
    func useCounter() {
        counter.increase()
        counter.increase()
        counter.decrease()
    }
}برای اینکه کدم تمیزتر شه متدهای دلیگیت رو توی یک اکستشن از کلاسم تعریف می‌کنم:extension MyClass: CounterDelegate {
    func counter(valueChanged from: Int, to: Int) {
        print(&amp;quotvalue changed from \(from) to \(to)&amp;quot)
    }
    func counter(reachedToGoal goal: Int) {
        print(&amp;quotcounter reached to goal: \(goal)&amp;quot)
    }
}حالا کافیه از کلاس MyClass یه آبجکت بسازم و متد useCounter رو فراخوانی کنم:let myClass = MyClass()
myClass.useCounter()نتیجه به صورت زیر خواهد بود:value changed from 0 to 1
value changed from 1 to 2
counter reached to goal: 2
value changed from 2 to 1سخن پایانیخب. فکر کنم الان دیگه می‌دونید زمانی که یک دلیگیت رو استفاده می‌کنید چه اتفاقی میوفته. علاوه بر این همونطور که اول کار هم گفتم این مطلب میتونه کمکتون کنه تا هم کد تمیزتری داشته باشین و هم اگر روزی خواستین کتابخونه ای برای سوییفت بسازین، بدونید چجوری توابع دلیگیت رو پیاده سازی کنید.اگر از این مطلب خوشتون اومد و مفید بود براتون لایک فراموش نشه لطفا ☺️?</description>
                <category>Pouya Yarandi</category>
                <author>Pouya Yarandi</author>
                <pubDate>Sat, 12 Oct 2019 18:51:01 +0330</pubDate>
            </item>
            </channel>
</rss>