<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های امید گل پرور</title>
        <link>https://virgool.io/feed/@Golparvar</link>
        <description>آی ام وان آو موست ادونسد هیومنوید اوپریتینگ سیستم! ?</description>
        <language>fa</language>
        <pubDate>2026-04-15 01:17:35</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/427/avatar/IWstVT.png?height=120&amp;width=120</url>
            <title>امید گل پرور</title>
            <link>https://virgool.io/@Golparvar</link>
        </image>

                    <item>
                <title>پیاده‌سازی عملگر دلخواه در سوییفت</title>
                <link>https://virgool.io/@Golparvar/how-to-create-a-custom-operator-in-swift-iwscrwe6ybag</link>
                <description>داشتم در مورد «مطابقت الگو» توی سوییفت می‌خوندم، که یه عملگر چشمم رو گرفت!!؛ اونم عملگر اختصاصی سوییفت برای این کار بود: =~ . از این عملگر میشه بعنوان مثال، توی بررسی کد HTTP پاسخ سرور استفاده کرد؛ که مثلا اگه موفق نبوده، کد دریافتی توی چه محدوده‌ای هست.if 400..&lt;500 ~= error.code, error.code != 401 {
        //Handle Error
}با اینکه ازش استفاده می‌کردم، ولی هیچ تصوری نداشتم که دقیقا داره چجوری کار می‌کنه؛ و حتی نمی‌دونستم که خودمون هم می‌تونم عملگرهای دلخواه خودمون رو داشته باشیم. تا اینکه از گوگل‌جان کمک گرفتم، و اونم هرچی می‌خواستم رو در اختیارم قرار داد. ?? توی این صفحه می‌تونین لیستی از عملگرهای سوییفت رو ببینین.انواع عملگرها در سوییفتتوی سوییفت، عملگرها توی چهار دسته‌بندی تقسیم میشن:دسته Infix : عملگر بین دو مقدار مورد استفاده قرار می‌گیره. مثل: &lt;Value1&gt; + &lt;Value2&gt;دسته Prefix : عملگر قبل از یه مقدار مورد استفاده قرار می‌گیره. مثل: &lt;Value1&gt;!دسته Postfix : عملگر بعد از یه مقدار مورد استفاده قرار می‌گیره. مثل: !&lt;Value2&gt; دسته Ternary : دوتا عملگر بین سه تا مقدار مورد استفاده قرار می‌گیرن. مثل: &lt;Value1&gt; ? &lt;Value2&gt; : &lt;Value3&gt;? توی سوییفت، راهی برای پیاده‌سازی عملگر دلخواه از دسته Ternary وجود نداره.چجوری یه عملگر دلخواه بسازیم؟خب. الان می‌خوایم برای نمونه، یه عملگر بسازیم تا جذر یه عدد رو بهمون بده. بهترین و قشنگ‌ترین کاری که می‌تونیم انجام بدیم، اینه که کاراکتر مربوط به اون عملگر رو برابر ( √ ) قرار بدیم!! ?? توی سوییفت تابعی هست به نام sqrt که میاد و جذر عدد ورودی خودش رو برمی‌گردونه. مام در نهایت از همین تابع استفاده خواهیم کرد؛ البته با روشی بمراتب خوشگل‌تر!! برای پیاده‌سازی این عملگر، طبیعی هست که باید از نوع Prefix باشه، و نحوه استفاده‌اش هم چیزی شبیه به این خواهد بود:let someVal = 25
let squareRoot = √someVal // result is 5مراحل قدم به قدم پیاده‌سازیاولین قدم اینه که کاراکتر مورد نظرمون رو بعنوان یه عملگر Prefix معرفی‌ش کنیم:prefix operator √قدم بعدی اینه که ما یه تابع (هم‌نام کاراکتر مورد نظرمون) تعریف کنیم. این تابع یه ورودی از نوع Double داره، و یه خروجی هم از نوع Double خواهد داشت. بدنه این تابع، در واقع میاد و جذر عدد ورودی رو حساب می‌کنه و اون رو برمی‌گردونه:prefix func √(lhs: Double) -&gt; Double {
        return sqrt(lhs)
}تمام!! نمونه اجرایی‌اش هم میشه اینجوری:prefix operator √
prefix func √(lhs: Double) -&gt; Double {
        return sqrt(lhs)
}

let number: Double = 36
let squareRoot = √number
print(squareRoot) // 6.0بیاین با استفاده از علامت ◉، یه عملگر infix بسازیماین عملگر دلخواه ما، دو تا مقدار به نام‌های lhs و rhs قبول می‌کنه و مجموع مربعات اونا رو برمی‌گردونه. بعنوان مثال اگه ورودی‌هاش ۲ و ۳ باشه، مقدار ۱۳ رو برمی‌گردونه.خب، مثل توضیحات قبلی، قدم به قدم می‌ریم جلو.اول عملگرمون رو با استفاده از علامت مورد نظرمون تعریف می‌کنیم:infix operator ◉قدم بعدی اینه که تابعی که در واقع بدنه اجرایی این عملگر هست رو تعریف کنیم:infix func ◉(lhs: Double, rhs: Double) -&gt; Double {
    return lhs * lhs + rhs * rhs
}اگه کدهای تا اینجا رو اجرا بگیرین، کامپایلر بهتون یه همچین خطایی رو نشون میده:error: ‘infix’ modifier is not required or allowed on func declarationsبرای رفع خطا، فقط کافیه کلمه infix رو از تعریف تابع حذف کنیم.تا اینجا ما یه عملگر اختصاصی با علامت و بدنه دلخواه‌مون تعریف کردیم. البته اینم در نظر بگیرین که این تمام ماجرا نیست، و یه قسمتی از تعریف این عملگر، از تنظیمات پیشفرض استفاده کرده. موارد دیگه‌ای که می‌تونیم برای عملگرمون تعریف کنیم (و در مواردی هم باید این کار رو انجام بدیم)، تقدم و شرکت‌پذیری عملگر هست، که در ادامه توضیحش رو میدیم.برای دیدن توضیحات در مورد تقدم و شرکت‌پذیری می‌تونین این صفحه در مورد ترتیب عملگرها و این صفحه در مورد تعریف عملگرها رو مطالعه کنین.تقدم و شرکت‌پذیرییکی از مهم‌ترین نکات توی تعریف عملگرها، تقدم (Precedence) و شرکت‌پذیری (Associativity) هست. این صفحه مستندات رسمی اپل برای این نکات توی سوییفت هست.بطور کلی،تقدم عملگرها، به بعضی از عملگرها اولویت بالاتری نسبت به بقیه عملگرها میده. این اولویت توی اجرا خودش رو نشون میده و عملگرهای با اولویت بالاتر، زودتر اجرا میشن.شرکت‌پذیری عملگرها، این رو مشخص می‌کنه که عملگرهای دارای اولویت یکسان یا برابر، به چه صورتی باهم دسته‌بندی میشن؛ به سمت چپ دسته‌بندی میشن یا به سمت راست.مثال زیر، نمونه‌ای از عملگرهایی هست که به سمت چپ دسته‌بندی میشن:v1 + v2 + v3 == (v1 + v2) + v3ترتیب اولویت عملگرهای سوییفت توی شکل زیر قابل مشاهده‌ست.Raywenderlich گرفته از وبسایت برای دیدن لیست کامل عملگرهای سوییفت و توضیحات مربوط به اونا، مستندات رسمی اپل در مورد عملگرهای سوییفت رو بخونین.عملگری که تعریف کردیم، دارای اولویت تعریف‌شده نیست. خودمون باید براش یه اولویت تعریف کنیم.یه گروه جدید اولویت با اسم SquareSumOperatorPrecedence تعریف می‌کنیم:precedencegroup SquareSumOperatorPrecedence {
    lowerThan: MultiplicationPrecedence
    higherThan: AdditionPrecedence
    associativity: left
    assignment: false
}توی کد بالا، ما یه گروه اولویت جدید ساختیم که اولویت اجراییش از AdditionPrecedence بیشتره، و از MultiplicationPrecedence کمتره و به سمت چپ دسته‌بندی میشه.مقادیر none و یا left و یا right ، مقادیر قابل قبول برای associativity هستن.توضیح در مورد assignment ، توی نسخه اصلی مقاله هست. خوندمش، ولی چون نتونستم درست متوجه بشم یا منظور رو برسونم، از ذکر توضیحش خودداری کردم.حالا که گروه اولویت رو تعریف کردیم، نحوه تعریف عملگر رو تغییر میدیم بطوریکه از گروه اولویتی که ما تعریف کردیم پیروی کنه:infix operator ◉: SquareSumOperatorPrecedenceدر نهایت کد ما یه همچین چیزی میشه://Create PrecedenceGroup
precedencegroup SquareSumOperatorPrecedence {
    lowerThan: MultiplicationPrecedence
    higherThan: AdditionPrecedence
    associativity: left
    assignment: false
}

//Create Infix Operator
infix operator ◉: SquareSumOperatorPrecedence

//Define Infix Operator
func ◉(lhs: Double, rhs: Double) -&gt; Double {
    return lhs * lhs + rhs * rhs
}

let a: Double = 2
let b: Double = 3
let squareSum = a ◉ b
print(squareSum) // 13.0خب بعدش؟برای قدم‌های بعدی می‌تونین در مورد Operator Overloading (نمی‌دونم چی‌چی ترجمه‌اش کنم!! ?) بخونین. Classها و Structها می‌تونن پیاده‌سازی اختصاصی خودشون از عملگرهای فعلی رو داشته باشن. این کار Overload کردن عملگرهای موجود نام برده میشه.struct Vector2D {
    var x = 0.0
    var y = 0.0
}

extension Vector2D {
    static func + (lhs: Vector2D, rhs: Vector2D) -&gt; Vector2D {
        return Vector2D(x: lhs.x + rhs.x, y: lhs.y + rhs.y)
    }
}همچنین می‌تونین در مورد کاربرد Genericها توی تعریف عملگرها بخونین. prefix operator ++++
prefix func ++++&lt;T: Numeric&gt;(lhs: T) -&gt; T {
    return lhs * 4
}
let n = 12
let m = ++++n
print(m) // 48منبع مطلب: این مطلب رو بر اساس این پست نوشتم.</description>
                <category>امید گل پرور</category>
                <author>امید گل پرور</author>
                <pubDate>Thu, 20 Sep 2018 14:56:52 +0430</pubDate>
            </item>
                    <item>
                <title>مدیریت بهتر Extensionها در سوییفت</title>
                <link>https://virgool.io/@Golparvar/better-way-to-manage-swift-extensions-in-ios-project-mbs6vteb2ocl</link>
                <description>یکی از باحال‌ترین قابلیت‌های زبان برنامه‌نویسی سوییفت، Extension و کاربردهای اونه. توی این مقاله نمی‌خوایم خود Extension و نحوه استفاده از اون رو یادآوری کنیم؛ ولی می‌خوایم یه راهکار معرفی کنیم، تا با استفاده از اون، استفاده از Extensionها یکم بهتر و باحال‌تر بشه. ?خب.فرض کنیم یه extension نوشتیم برای UIColor که میاد از رنگ انتخابی ما، یه عکس یا همون UIImage تولید می‌کنه.extension UIColor { 
    func toImage() -&gt; UIImage { 
        let color = self 
        let rect = CGRect(x: 0, y: 0, width: 1, height: 1) 
        UIGraphicsBeginImageContext(rect.size) 
        let context = UIGraphicsGetCurrentContext()        
        context!.setFillColor(color.cgColor)        
        context!.fill(rect) 
        let img = UIGraphicsGetImageFromCurrentImageContext() 
        UIGraphicsEndImageContext() 
        return img!    
    }
}و بصورت زیر هم می‌تونیم ازش استفاده کنیم:let redImage = UIColor.red.toImage()مشکلی هم نیست. بهمین راحتی، بهمین خوشمزگی. ?ولی...!افتاد مشکل‌ها!۱. مشکل اول توی پیاده‌سازی ما، اینه که وقتی یه نفر بیاد و این کد رو ببینه، نمیتونه تشخیص بده که متد toImage() از متدهای استاندارد و اصلی خود UIColor هست یا نه!۲. مشکل بعدی، اینه که اگه هرکدوم از کتابخانه‌هایی که توی پروژه ازشون استفاده می‌کنیم، یه Extension روی UIColor تعریف کرده باشن و داخلش یه متد مثل متد ما تعریف کرده باشن چی؟!راه حلیه راه حل برای مشکل پیشرو، اینه که خیلی راحت، به همه متدهایی که تعریف می‌کنیم، یه پیشوند مثل my_ و یا omid_ اضافه کنیم.extension UIColor {
    func omid_toImage() -&gt; UIImage {
        let color = self
        let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
        UIGraphicsBeginImageContext(rect.size)
        let context = UIGraphicsGetCurrentContext()
        context!.setFillColor(color.cgColor)
        context!.fill(rect)
        let img = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return img!
    }
}

...

let redImage = UIColor.red.omid_toImage()این راه حل ممکنه در نگاه اول خوب باشه، ولی اگه ما روی بیست‌تا کلاس مختلف، مجموعا ۱۰۰ تا متد دلخواه با استفاده از Extension تعریف کرده باشیم چی؟! باید مطمئن بشیم که پیشوند انتخابی‌مون، به ابتدا تمام متدها اضافه بشه. استفاده از Protocol؛ راه حل اصلینظرتون چیه به جای my_toImage() از my.toImage() استفاده کنیم؟!رویه اینه که یه کلاس/ساختمان تعریف می‌کنیم، و همه متدهامون رو با استفاده از اون، و مفهوم Protocol و Extension، خیلی هوشمندانه و باحال اضافه می‌کنیم. ?import UIKit

public protocol MyHelperCompatible {
    associatedtype someType
    var my: someType { get }
}

public extension MyHelperCompatible {
    public var my: MyHelper&lt;Self&gt; { 
        get { 
            return MyHelper(self) 
        }
    }
}

public struct MyHelper&lt;Base&gt; {
    let base: Base
    init(_ base: Base) { 
        self.base = base
    }
}

// All conformance here
extension UIColor: MyHelperCompatible {}پروتوکل MyHelperCompatible که تعریف کردیم، یه مشخصه به اسم my داره، که میاد و جایگزین اون کلاس/ساختمان مورد بحث میشه.بعدش میایم و بر اساس مورد استفاده‌مون، MyHelper رو گسترش می‌دیم:import Foundation
import UIKit

extension MyHelper where Base: UIColor {
    func toImage() -&gt; UIImage { 
        let color = self.base
        let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
        UIGraphicsBeginImageContext(rect.size)
        let context = UIGraphicsGetCurrentContext()
        context!.setFillColor(color.cgColor)
        context!.fill(rect) let img = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext() 
        return img!
    }
}در واقع با استفاده از کد بالا، (و البته تعریف ساختمان MyHelper) داریم می‌گیم، اگه نوع پایه‌ای مورد استفاده برای MyHelper از نوع UIColor بود، این متد toImage رو بهش اضافه کن. و بصورت زیر هم می‌تونیم ازش استفاده کنیم:let redImage = UIColor.red.my.toImage()همین رویه رو می‌تونیم برای اضافه کردن متدهای مورد نظرمون، به انواع مختلف داده، بکار ببریم. و اینکه هر موقع خواستیم این متدها دیگه در دسترس نباشن، می‌تونیم خطی که باهاش نوع داده رو با پروتوکل تعریف شده هماهنگ می‌کنه، حذف یا کامنت کنیم.// extension UIColor: MyHelperCompatible {}نکات پایانی? برای اینکه مطالب این مقاله و نحوه پیاده‌سازی و کارکرد رو کامل متوجه بشیم، باید با مفاهیم Protocol، Extension، Generic آشنایی داشته باشیم.? ممکنه پیاده‌سازی همچین چیزی، بار اول، یکم پیچیده و نامفهوم باشه، ولی در نهایت کمک زیادی می‌کنه. در آخر، می‌تونین از همین رویه، برای آماده‌کردن و پیاده‌سازی یه Framework مثل PersianSwift استفاده کنین، و مطمئن باشین که متدهاتون با بقیه متدها و فریم‌ورک‌ها هم‌زیستی خواهند داشت! ?? منبع مطلب: این مطلب رو بر اساس این پست نوشتم.</description>
                <category>امید گل پرور</category>
                <author>امید گل پرور</author>
                <pubDate>Tue, 20 Feb 2018 19:57:09 +0330</pubDate>
            </item>
                    <item>
                <title>استفاده از Breakpointها</title>
                <link>https://virgool.io/@Golparvar/edit-breakpoints-in-xcode-uvtbwunqflka</link>
                <description>توى روند عیب‌زدایى و تست اپ‌ها، Breakpointها نقش خیلى مهمى دارن، و ایکس‌کد هم راه کارهاى جالبى براى استفاده از اونا ارائه میده. توى این متن، به بعضى از ترفندهایى که میشه موقع استفاده از Breakpointها بکار برد، اشاره می‌کنیم. خب. فرض می‌کنیم یه حلقه مثل کد زیر داریم:var sum = 0 
for i in 0...100 {
    sum += i 
} 
print(sum)? خواسته: میخوام وقتى متغیر i برابر ۶۰ شد، مقدار sum رو بدونم چیه. براى اینکار از اعمال شرط روى Breakpoint می‌تونیم استفاده کنیم. مراحلش هم به این صورته:١. خود Breakpoint رو داخل حلقه، و روى خطى که مقدار sum تغییر می‌کنه، تنظیم می‌کنیم. ٢. روى Breakpoint ایجاد شده دوبار کلیک می‌کنیم، و یا راست کلیک می‌کنیم و Edit رو می‌زنیم. ٣. داخل فیلد Condition عبارت i == 60 رو می‌نویسیم. حالا می‌دونیم زمانیکه مقدار i برابر ۶۰ بشه، مقدار sum برابر ۱۷۷۰ هست. البته این مقدار بدست اومده، قبل از انجام خطى هست که مورد نظر ما بوده. ? خواسته: میخوام مقدار sum رو فقط زمانى بدونم، که مقدار i بزرگتر یا برابر ۹۰ باشه. براى اینکار، می‌تونیم از گزینه Ignore که زیر فیلد Condition هست استفاده کنیم. و فقط کافیه مقدارش رو برابر ۹۰ قرار بدیم. بعد از اینکار، زمانیکه i به ۹۰ برسه، و دفعات بعدش، Breakpoint ما اعمال میشه و می‌تونین دیباگ رو انجام بدین. ⚠️ نکته: توجه داشته باشین که گزینه Ignore، میاد و به تعداد دفعاتی که مشخص کردین، Breakpoint رو در نظر نمی‌گیره. ما اینجا از این گزینه استفاده کردیم، چون میدونیم حلقه‌اى که تعریف کردیم، داراى گام حلقه برابر با یک هست؛ و اگه iهاى بین ٠ تا ٨٩ رو در نظر نگیریم، عین این می‌مونه که ٩٠ بار این Breakpoint رو در نظر نگرفتیم. ? خواسته: میخوام مقدار sum رو براى iهاى بزرگتر یا مساوى ٩٠ بدونم، ولى حالش رو ندارم هر بار این مقدار رو توى پنل دیباگ ببینم و بعدش دستى برنامه رو Continue کنم!! ?براى اینکار میتونین از Actionها استفاده کنین. مراحلش هم به این صورته:١. مقدار مورد نظرتون رو داخل Ignore تنظیم کنین. ٢. گزینه Add Action رو بزنین و فیلدش رو هم بنویسین po sum. این دستور مقدار sum رو پرینت میکنه.٣. گزینه Options رو فعال کنین. اینم براى اینه که اجراى برنامه بطور خودکار ادامه پیدا کنه. ٤. (دلخواه) اگه بخواین ببینین توى چه تابعى Breakpoint شما اعمال شده، میتونین از گزینه Log Message مربوط به Add Action استفاده کنین. همونطور که توى عکس هم میبینین، براى Log Message از اسم Breakpoint استفاده شده و حالا تمام اطلاعاتى که میخواستیم رو برامون چاپ میکنه.توی این مقاله، ما فقط یه سری استفاده‌های پایه‌ای از Breakpoint رو اشاره کردیم؛ و برای کسب اطلاعات در مورد کاربردهای دیگه Breakpoint و بطور کلی کارکرد ابزارهای مخصوص دیباگ ایکس‌کد، می‌تونین مستندات اپل در مورد ابزار دیباگ رو مطالعه کنین.? منبع مطلب: این مطلب رو بر اساس این پست نوشتم.</description>
                <category>امید گل پرور</category>
                <author>امید گل پرور</author>
                <pubDate>Sun, 18 Feb 2018 12:42:37 +0330</pubDate>
            </item>
                    <item>
                <title>سطوح دسترسی در سوییفت</title>
                <link>https://virgool.io/@Golparvar/everything-you-need-to-know-about-swift-access-modifiers-pjqnlkfa9pim</link>
                <description>خیلی سریع: سوییفت ۴ دارای ۵ سطح دسترسی مختلف هست. سطح دسترسی Openسطح دسترسی Open دارای حداقل محدودیت توی سطوح دسترسی هست. موجودیت‌هایی که با این سطح دسترسی تعریف میشن، خارج از ماژول (module یا target) خودشون می‌تونن مورد استفاده قرار بگیرن و همچنین می‌تونن در هر ماژولی خارج از ماژول خودشون، اصطلاحا Subclass و Override بشن. این همون دلیلی هست که ما وقتی UIKit رو توی اپ خودمون استفاده می‌کنیم، می‌تونیم مثل متدهای UITableView رو Override کنیم.سطح دسترسی Publicمثل سطح دسترسی Open، این سطح دسترسی هم اجازه استفاده از موجودیت‌ها خارج از ماژول خودشون رو صادر می‌کنن. ولی، بر خلاف Open که اجازه می‌داد خارج از ماژول اصلی، موجودیت‌ها Subclass یا Override بشن، سطح دسترسی Public اجازه میده فقط عملیات Subclass و Override داخل خود ماژول اصلی اتفاق بیوفته. مقایسه بین Open و Public// First.framework – A.swift
open class A { }// First.framework – B.swift
public class B: A { } // ok// Second.framework – C.swift
import First
class C: A {} // ok// Second.framework – D.swift
import First
class D: B { } // error: B cannot be subclassedکلاسی که با Open تعریف شده، توی ماژول‌های دیگه می‌تونه Subclass بشه. همچنین، موجودیت‌های کلاس Open می‌تونه توی ماژول‌های دیگه Override هم بشه. در طرف دیگه، کلاسی که با Public تعریف شده، توی ماژول‌های دیگه میتونه مورد استفاده قرار بگیره، ولی نمی‌تونه Subclass و یا Override بشه.سطح دسترسی Internalموجودیت‌هایی که با این سطح دسترسی تعریف می‌شن، توی کل ماژول (target) خودشون در دسترس هستن، ولی خارج از ماژول خودشون، نه. این رو هم در نظر بگیرین که اگه برای موجودیت‌ها از هیچ سطح دسترسی استفاده نشه، این سطح دسترسی (بعنوان سطح دسترسی پیشفرض) مورد استفاده قرار می‌گیره.// First.framework – A.swift 
internal struct A {}  
// First.framework – B.swift 
A() // ok  
// Second.framework – C.swift 
import First 
A() // error: A is unavailableسطح دسترسی FilePrivateاین سطح دسترسی استفاده از موجودیت‌ها رو، به فایل کدی (Source File) که موجودیت داخلش تعریف شده محدود می‌کنه.سطح دسترسی Privateاین سطح دسترسی، استفاده از موجودیت‌ها رو به محدوده تعریفش، و همچنین به Extensionهایی که داخل همون فایل کد هستن، محدود می‌کنه.سطح دسترسی Finalاز نسخه ۳ سوییفت، میشه final رو به هر سطح دسترسی اضافه کرد، بجز Open. موجودیت‌هایی که با استفاده از این کلمه تعریف میشن، (همونطور که از اسمش هم پیداست، نمونه نهایی در نظر گرفته میشن و) اصطلاحا Override و Subclass نمیشن. اینم که برای سطح Open نمیشه از این کلمه استفاده کرد، بخاطر ذات خود Open هست، که برای ایجاد امکان Override و Subclass هست.یه تغییر کوچک توی سوییفت ۴سوییفت ۴ با تغییر محدوده دسترسی به موجودیت‌های Private، استفاده از fileprivate رو برای Extensionها کاهش داده. قبل از سوییفت ۴، سطح دسترسی private اجازه از موجودیت، داخل Extension رو نمی‌داد:class A {
    private var flag = false
}extension A {
     func isFlagSet() -&gt; Bool {
          return flag
          // Error in Swift 3 
          // Works fine in Swift 4
    }
}توی سوییفت ۳، مشکل این بود که موجودیت‌هایی که با سطح دسترسی private تعریف می‌شدن، اجازه دسترسی از طریق Extensionها، حتی اگه توی یک فایل بودن رو هم، نداشتن. راه حل هم این بود که همه اون privateها رو به fileprivate تغییر بدیم. این مشکل توی نسخه ۴ حل شده، و دیگه برای استفاده از موجودیت‌های private داخل Extensionها، نیازی نیست اونا رو با fileprivate تعریف کنیم.? برای اطلاعات بیشتر، می‌تونین لینک‌های زیر رو ببینین:لینک اول: وبلاگ زبان برنامه‌نویسی سوییفتلینک دوم: مستندات وبسایت اپل? منبع مطلب: این مطلب رو بر اساس این پست نوشتم.</description>
                <category>امید گل پرور</category>
                <author>امید گل پرور</author>
                <pubDate>Sat, 17 Feb 2018 23:16:47 +0330</pubDate>
            </item>
                    <item>
                <title>جایگزینی flatMap با compactMap در نسخه ۴.۱ سوییفت</title>
                <link>https://virgool.io/@Golparvar/replacing-flatmap-with-compactmap-utqf1r148kqt</link>
                <description>نسخه ۴.۱ زبان برنامه‌نویسی سوییفت بهمراه ایکس‌کد ۹.۳ (که در زمان نگارش این متن، هنوز بتاست) منتشر شده، و تغییرات جدیدی رو توی خود زبان و همینطور کتابخانه‌های استاندارد خودش داشته.استفاده از flatMap که روی انواع ترتیبی داده‌ها (مثل آرایه‌ها) اعمال میشه، و تمام المان‌هایی که خروجی‌شون nil هست رو فیلتر می‌کنه، توی نسخه ۴.۱ با استفاده از متد compactMap انجام میشه؛ و این مورد استفاده flatMap توی نسخه ۴.۱ اصطلاحا deprecate شده. خلاصه تغییر مورد بحثبرای حذف nilها از یه آرایه، از flatMap استفاده می‌کنین:let names: [String?] = [&quot;Tom&quot;, nil, &quot;Peter&quot;, nil, &quot;Harry&quot;]
let valid = names.flatMap { $0 } 
// [&quot;Tom&quot;, &quot;Peter&quot;, &quot;Harry&quot;]و ایکس‌کد ۹.۳ یه اخطار برای این نوع استفاده از flatMap بهتون نشون میده:راه حل پیشنهادی خود ایکس‌کد هم جایگزینی flatMap با compactMap هست:let names: [String?] = [&quot;Tom&quot;, nil, &quot;Peter&quot;, nil, &quot;Harry&quot;]
let valid = names.compactMap { $0 }
// [&quot;Tom&quot;, &quot;Peter&quot;, &quot;Harry&quot;]هر زمان که از flatMap روی یه Sequence استفاده کنین، و اون flatMap یه مقدار Optional رو برگردونه، ایکس‌کد همین رفتار رو خواهد داشت. (خداییش هر کلمه فارسی بجای Optional استفاده می‌کردم، هیچکس نمیفهمید چی‌چی می‌گم ?)پس توی مثال زیر هم، باز ایکس‌کد همون اخطار رو میده:let words = [&quot;53&quot;, &quot;nine&quot;, &quot;hello&quot;,&quot;0&quot;]
let values = words.flatMap { Int($0) }اینجا هم، با تغییر flatMap به compactMap اخطار ایکس‌کد رفع میشه:let values = words.compactMap { Int($0) }
// Returns [Int] // [53, 0]بیشتر بدانید!? اول از همه، نسخه ۴.۱ سوییفت، تمام موارد استفاده از flatMap رو Deprecate نکرده؛ در واقع فقط یک روند استفاده رو اخطار میده.توی سوییفت ۴.۰، سه رویه هست که می‌تونین از flatMap استفاده کنین:استفاده از flatMap روی یه Sequence بهمراه یه closure که Sequence بر می‌گردونه:Sequence.flatMap&lt;S&gt;(_ transform: (Element) -&gt; S)  -&gt; [S.Element] where S : Sequenceبا استفاده از این رویه، از flatMap استفاده می‌کنین، و بعنوان مثال آرایه‌ای از آرایه رو، به یک آرایه (که شامل همه اعضای آرایه‌هاست) تبدیل می‌کنین:let scores = [[5,2,7], [4,8], [9,1,3]]
let allScores = scores.flatMap { $0 }
// [5, 2, 7, 4, 8, 9, 1, 3]
let passMarks = scores.flatMap { $0.filter { $0 &gt; 5} }
// [7, 8, 9]سوییفت ۴.۱ کاری به کار این روند نداره! ?استفاده از flatMap روی نوع داده Optional:توی این روند استفاده، flatMap یه closure می‌گیره که اونم یه Optional بر می‌گردونه! (دقیقش رو نمی‌دونم که چه استفاده‌ای داره این کار! اگه کسی می‌دونه بگه)Optional.flatMap&lt;U&gt;(_ transform: (Wrapped) -&gt; U?) -&gt; U?
let input: Int? = Int(&quot;8&quot;)
let passMark: Int? = input.flatMap { $0 &gt; 5 ? $0 : nil}
// Optional(8)بهرحال، سوییفت ۴.۱ به این یکی هم کاری نداره!استفاده از flatMap روی یه Sequence و بهمراه یه Closure که می‌تونه Optional برگردونه:Sequence.flatMap&lt;U&gt;(_ transform: (Element) -&gt; U?) -&gt; U?این همون کاربردی هست که توی سوییفت ۴.۱ تغییر کرده؛ و برای همچین کاری، باید flatMap رو با compactMap جایگزین کنیم.let names: [String?] = [&quot;Tom&quot;, nil, &quot;Peter&quot;, nil, &quot;Harry&quot;]
let counts = names.compactMap { $0?.count }
// [3, 5, 5]ایده پیاده‌سازی compactMap احتمالا بخاطر گویایی بیشتر نام تابع هست؛ «با حذف المان‌های nil از یه آرایه، آرایه رو داریم فشرده می‌کنیم». حتی ممکنه در آینده، و در نسخه‌های بعدی سوییفت یه متد اضافه کنن به اسم compact که بدون اینکه خروجی داشته باشه، با حذف المان‌های nil، یه آرایه رو (در جا) فشرده می‌کنه.? برای اطلاعات بیشتر، می‌تونین مستندات مربوط به این تغییرات رو در این آدرس ببینین.? منبع مطلب: این مطلب رو بر اساس این پست نوشتم.</description>
                <category>امید گل پرور</category>
                <author>امید گل پرور</author>
                <pubDate>Fri, 16 Feb 2018 21:16:34 +0330</pubDate>
            </item>
                    <item>
                <title>اخطارهای مربوط به @objc بعد از مهاجرت به سوییفت ۴</title>
                <link>https://virgool.io/@Golparvar/objc-warnings-upgrading-to-swift-4-hjf34qj8tm8v</link>
                <description>وقتی یه پروژه نوشته شده با سوییفت ۳ رو با ایکس‌کد نسخه ۹ باز می‌کنین، ایکس‌کد بهتون پیام میده که می‌تونین پروژه رو به نسخه ۴ سوییفت ارتقاء بدین. اگه این ارتقاء رو بپذیرین، ایکس‌کد یه پیام دیگه بهتون میده که «قوانین بررسی و استفاده متدها و مشخصه‌های @objc توی نسخه ۳ سوییفت، توی نسخه ۴ منقضی شدن». حالا این اخطارها چی هستن و چجوری رفع میشن؟! نگران نباشین، من اینجام! ?حالا این استنتاج @objc چی هست؟!صادقانه بگم، تا قبل اینکه سوییفت ۴ قوانین مورد استفاده رو تغییر بده، این @objc چیزی نبود که بخوام زیاد روش وقت بذارم یا بهش توجه کنم. شما می‌تونین @objc رو به مشخصه‌ها و متدهای سوییفت اضافه کنین، تا اونا بتونن توسط کدهای Objective-C قابل دسترس باشن. خود مترجم (Compiler) هم یه سری قوانین برای این کار داره و تا جایی که بتونه کمک شما می‌کنه.مترجم سوییفت ۳ در مورد اضافه کردن @objc یکم زیادی ولخرجی می‌کنه! و حتی اون رو زمانی هم که بهش نیازی نیست، اضافه می‌کنه. این رویه باعث افزایش حجم خروجی برنامه‌ها میشه، چون همه اون مشخصه‌ها و متدهایی که بهشون @objc اضافه میشه، کدهایی دیگه‌ای هم خواهند داشت تا بتونن توسط Objective-C مورد استفاده قرار بگیرن.مترجم سوییفت ۴، یکم محافظه‌کار شده! و @objc رو توی موارد خاصی اضافه می‌کنه. بعنوان مثال، زمانیکه شما دارین متدهای دارای @objc رو اصطلاحا override می‌کنین، و یا یه پروتکل دارای @objc رو پیاده‌سازی می‌کنین. برای همین، نیازی نیست تمام متدهایی که برای UITableViewDataSource هست رو، وقتی استفاده می‌کنین، با @objc بنویسین. همچنین موقع استفاده از @IBOutlet، @IBAction و یا @IBInspectable هم نیازی به نوشتن @objc نیست. این قوانین، یکم کار رو برای ارتقاء به سوییفت ۴ راحت‌تر می‌کنه، ولی آخرش یه سری کارا رو خودتون باید دستی انجام بدین.ارتقاء پروژه به نسخه ۴ سوییفتوقتی یه پروژه نوشته شده با سوییفت ۳ رو با ایکس‌کد ۹ باز می‌کنین، بهتون یه پیام میده با این مظمون که «تبدیل به نسخه ۴ شدنیه!!» ?.این که اصطلاحا Build Warning داشته باشیم، یکم رو اعصابه!! ولی شما مجبور به ارتقاء پروژه به نسخه ۴ سوییفت نیستین. ایکس‌کد ۹، در کنار نسخه ۴، از نسخه ۳.۲ هم پشتیبانی می‌کنه؛ و این کار از طریق تنظیمات پروژه انجام میشه. اگه شما بخواین پروژه رو ارتقاء بدین، روی این اخطاری که ایکس‌کد بهتون داده کلیک می‌کنین، و ایکس‌کد ابزار ارتقاء پروژه رو بهتون نشون میده، و شما اول اون Target که می‌خواین ارتقاء بدین رو انتخاب می‌کنین، و بعدش دو تا گزینه جلوتون هست:کمینه‌سازی استنتاج: این گزینه پیشنهادی خود ایکس‌کد هست. با این رویه، ابزار ارتقاء، میاد و @objc رو فقط اون مواردی به کد شما اضافه می‌کنه که مطمئن هست که باید اضافه بشه. مثل متدهایی که بواسطه #selector مورد استفاده قرار می‌گیرن. این رویه، یکم باعث کاهش حجم خروجی اپ شما میشه (و نمی‌دونم این کاهش حجم توی اپ‌های متوسط محسوس هست یا نه)، و شما برای تکمیل این روند، یه سری کار دیگه هم هست که باید انجام بدین.مطابقت با نسخه ۳ سوییفت: با استفاده از این گزینه، در واقع ما داریم می‌گیم، ولمون کن، همون رویه که برای نسخه ۳ پیش می‌گرفتی، دوباره پیش بگیر!! طبق مستندات، انتخاب این گزینه خطری برای پروژه شما نخواهد داشت. بازم میگم، اگه گزینه پیشنهادی رو انتخاب کنین، یه سری کار دیگه هم برای تکمیلش باید انجام بدین. این قدم‌های بعدی، توسط خود ایکس‌کد، بصورت یه لینک (که فقط هم یبار نشونش میده!!) در دسترس شما قرار می‌گیره. البته می‌تونین از طریق قسمت Help خود ایکس‌کد، توی بخش Work In Xcode بهش دسترسی داشته باشین.? نمی‌خواد دنبالش بگردین؛ لینکش اینه !!بعد از قدم‌های اولیه، ایکس‌کد که کاراش تموم شد، یه همچین پیامی به شما نشون میده:اگه از قسمت تنظیمات پروژه، مشخصه مربوط به استنتاج @objc رو بررسی کنین، می‌بینین که این رویه هنوزم قوانین مربوط به سوییفت ۳ داره استفاده میشه:این گزینه برای این خوبه، چون هر زمان که کدی مورد استفاده قرار بگیره که یه @objc جا انداخته، اخطارهایی در زمان Build و زمان اجرا بهتون نشون داده میشه، و شما می‌تونین برای رفع این اخطارها اقدام کنین.تصحیح دستی کدها و تنظیمات پروژهزمانیکه شما می‌خواین یه پروژه تماما سوییفت رو ارتقاء بدین، معمولا ابزار بروزرسانی کدها که توسط خود ایکس‌کد مورد استفاده قرار می‌گیره، تا حد زیادی خوب عمل می‌کنه، و خودش هرجا نیاز ببینه، @objc رو اضافه می‌کنه. مثلا وقتی شما از #selector استفاده می‌کنین، خودش این @objc رو به اول تعریف متد مورد استفاده اضافه می‌کنه.button.addTarget(self, action: #selector(doAction(sender:)), for: .touchUpInside)از اونجایی که متد مورد نظر شما باید از طریق UIKit صدا زده بشه، در نتیجه باید توسط کدهای Objective-C قابلیت دسترسی داشته باشه. برای همین، ابزار بروزرسانی کد ایکس‌کد، میاد و به اول تعریف متد، @objc رو اضافه می‌کنه:@objc func doAction(sender: UIButton) {
    // Do action here 
}اگه شما روی یه پروژه ترکیبی Objective-C و Swift کار می‌کنین، یه سری کارا رو خودتون باید دستی انجام بدین. مثلا فرض کنین یه همچین کلاسی تعریف کردیم:public class MyModel: NSObject {
    var someFlag = false
    func doSomething() {
        print(&quot;doing something&quot;)
    }
}بطور پیشفرض توی نسخه ۳ سوییفت، مشخصه‌ها و متدها یه کلاس که زیر کلاس NSObject باشه، از طریق Objective-C قابلیت دسترسی داره (مگه اینکه بصورت private تعریف شده باشه).self.model.someFlag = YES;
[self.model doSomething];توی نسخه ۴، این رویه دیگه برقرار نیست، و شما با خطاها و اخطارهای زیر روبرو می‌شین:برای رفع این خطاها، می‌تونیم @objc رو به مشخصه‌ها و متدها اضافه کنیم:public class MyModel: NSObject {
    @objc var someFlag = false
    @objc func doSomething() {
        print(&quot;doing something&quot;)
    }
}اگه شما مطمئن باشین که می‌خواین کل مشخصه‌ها و متدهای یه کلاس رو قابل دسترس برای Objective-C بکنین، می‌تونین از یه معرف دیگه به اسم @objcMembers استفاده کنین:@objcMembers
public class MyModel: NSObject {
    var someFlag = false    // @objc
    func doSomething() {    // @objc 
        print(&quot;doing something&quot;)
    }
}استفاده از @objcMembers، بطور پیشفرض، دسترسی به متدهای یه کلاس رو، به متدهای تعریف شده داخل extension های کلاس هم اعمال می‌کنه. در نتیجه کد بالا، با کد پیش رو، معادل میشه:public class MyModel: NSObject {
    @objc var someFlag = false
}

@objc extension MyModel {
    func doSomething() {
        print(&quot;doing something&quot;)
    }
}? توجه داشته باشین،چون extensionها نمی‌تونن دارای اصطلاحا Stored Propertieها باشن، نمی‌تونیم اون someFlag رو به extension منتقل کنیم.همچنین برای جلوگیری از رفتار پیشفرض @objc (برای مثال روی Extensionها)، می‌تونیم از @nonobjc استفاده کنیم:@objc extension MyModel {
    func doSomething() {
        print(&quot;doing something&quot;)
    }
    @nonobjc func doNothing() { // Not accessibile from objc 
        // ...
    }
}تکمیل روند مهاجرتزمانیکه مطمئن شدین همه خطاها و اخطارها رو رفع کردین، و پروژه دیگه مشکل خاصی با نسخه ۴ سوییفت نداره، باید از طریق تنظیمات مربوط به پروژه، برای همه Targetها، گزینه مربوط به استنتاج @objc رو تغییر بدین:با تغییر این گزینه به Default، آخرین قدم رو برداشتین، و می‌تونین روند پیشبرد پروژه رو ادامه بدین. ? برای اطلاعات بیشتر، می‌تونین فیلم مربوط به نشست WWDC که درباره محدودسازی استنتاج @objc هست رو در این آدرس ببینین،? و یا از مستندات خود اپل توی این آدرس استفاده کنین.? منبع مطلب: این مطلب رو بر اساس این پست نوشتم.</description>
                <category>امید گل پرور</category>
                <author>امید گل پرور</author>
                <pubDate>Fri, 02 Feb 2018 23:55:33 +0330</pubDate>
            </item>
                    <item>
                <title>تنظیمات مربوط به حریم شخصی در اپ‌های آی‌او‌اس ۱۰</title>
                <link>https://virgool.io/@Golparvar/privacy-settings-in-ios-10-wh2lkgiccqbv</link>
                <description>از مدت‌ها پیش، در سیستم‌عامل آی‌او‌اس، برای اینکه یه اپ بتونه به اطلاعات شخصی کاربر (مثل عکس‌ها و یا مخاطبین) دسترسی داشته باشه، باید اول از کاربر سوال می‌کرد و ازش اجازه می‌گرفت. (البته این اجازه، در هر زمانی که کاربر بخواد، از طریق منو تنظیمات قابل ویرایش هست)توی نسخه ۱۰ از سیستم‌عامل آی‌او‌اس، اپل محدوده اطلاعاتی که جزء اطلاعات شخصی کاربر محسوب میشه رو بیشتر کرده؛ بطوریکه الان موزیک‌های کاربر هم جزء اطلاعات شخصی کاربر بحساب میاد.تغییر قابل توجه دیگه‌ای که توی نسخه ۱۰ اعمال شده، اینه که برنامه‌نویس باید از قبل، این دسترسی‌ها رو مشخص کنه؛ وگرنه در زمان اجرا، اپ کرش می‌کنه! راه حل این موضوع هم سریعه و هم ساده. پس اگه می‌خواین اپ خودتون رو برای آی‌او‌اس ۱۰ بهینه کنین، ادامه رو هم بخونین.یادتون باشه یه متن مناسب برای گرفتن اجازه از کاربر تهیه کرده باشینزمانیکه دارین اپ آی‌او‌اس رو برای نسخه ۱۰ بهینه می‌کنین، باید از قبل، تمام دسترسی‌ها به اطلاعات شخصی کاربر رو مشخص کنین. این روند با استفاده از اضافه کردن کلیدهای مشخص به فایل Info.plist بهمراه پیام مورد نظرتون (که مثلا این دسترسی برای چی داره گرفته میشه) انجام میشه. لیست فریم‌ورک‌هایی که برای استفاده‌شون به مجوز کاربر نیاز هست ایناست:Contacts, Calendar, Reminders, Photos, Bluetooth Sharing, Microphone, Camera, Location, Health, HomeKit, Media Library, Motion, CallKit, Speech Recognition, SiriKit, TV Provider.اگه هر کدوم از این فریم‌ورک‌ها رو بخواین استفاده کنین، ولی کلید مربوطه بهمراه پیام رو داخل فایل Info.plist ثبت نکرده باشین، در اولین دسترسی به این فریم‌ورک‌ها، برنامه کرش می‌کنه. البته گزارشی که در زمان این کرش داده میشه، خیلی مشخص به شما میگه که کدوم فریم‌ورک رو می‌خواستین استفاده کنین، بعلاوه اینکه چه کلیدی رو باید اضافه می‌کردین که نکردین. برای مثال، این پیامی هست که در زمان استفاده از دوربین دستگاه، بدون ثبت کلید مربوطه، به شما نشون داده میشه:This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app’s Info.plist must contain an NSCameraUsageDescription key with a string value explaining to the user how the app uses this data.برای جلوگیری از این کرش، نیاز هست که کلیدی که توی گزارش هم نام برده شده، به فایل Info.plist اضافه بشه. خوشبختانه از ایکس‌کد نسخه ۸، همه کلیدها براحتی قابل دسترسی هست:بعد از این روند، در اولین دسترسی به دوربین، سیستم‌عامل پیام شما رو برای کسب اجازه از کاربر نشون میده:? برای اطلاعات بیشتر، می‌تونین فیلم مربوط به نشست WWDC که درباره حریم شخصی کاربران هست رو در این آدرس ببینین. ? منبع مطلب: این مطلب رو بر اساس این پست نوشتم.</description>
                <category>امید گل پرور</category>
                <author>امید گل پرور</author>
                <pubDate>Fri, 02 Feb 2018 18:52:29 +0330</pubDate>
            </item>
                    <item>
                <title>افزایش خودکار شماره ساخت اپ، توی ایکس کد</title>
                <link>https://virgool.io/@Golparvar/auto-incrementing-build-numbers-in-xcode-yxrrnipisnro</link>
                <description>خیلی سریع می‌ریم سر اصل مطلب ?.توی پروژه‌های مربوط به برنامه‌های iOS، نسخه اپ، با دو تا عدد مشخص میشه. یکی شماره اصلی نسخه، و یکی دیگه شماره ساخت (یا همون Build Number) هست. ترکیب این دو تا عدد، نسخه اپ رو مشخص می‌کنه. این دو تا عدد با اسم‌های زیر بکار میرن:متن کوتاه نسخه اپ (یا Short Bundle Version String، که ما بعنوان شماره اصلی صداش زدیم)شماره ساخت (یا Build Number)برای نمونه می‌تونین این عکس رو ببینین:در کنار اسم اپ و مشخصه اپ، شماره اصلی نسخه، و شماره ساخت هم قابل مشاهده و ویرایش هسترویه به این صورت هست خروجی‌هایی که شما از پروژه می‌گیرین، میتونن دارای شماره اصلی یکسان، و یک یا چندین شماره ساخت باشه. مثلا چهار تا خروجی داریم که همه‌شون شماره نسخه ۱.۶ هستن، ولی با شماره ساخت‌های ۱۰۰۰، ۱۰۰۱، ۱۰۲۰ و ۱۰۵۰. توجه داشته باشین که اگه ما شماره اصلی رو ثابت نگه داریم، و شماره ساخت رو تغییر بدیم، این خروجی‌ها، توسط پنل آی‌تونز (یا iTunes Connect) بعنوان نسخه‌های مجزا شناخته میشن.برای مثال، عکس زیر. این عکس خروجی‌هایی هست که برای اپ «مثقال» گرفته شده و روی پنل آی‌تونز بارگذاری شده، تا با استفاده از تست‌فلایت (TestFlight ابزار کمکی اپل هست که برای روند تست اپ‌ها مورد استفاده قرار می‌گیره)، تست‌کننده‌ها بتونن نسخه‌های مختلف (چه از نظر شماره اصلی نسخه، و چه از نظر شماره ساخت) رو روی دستگاه‌هاشون نصب و تست کنن؛ و تیم پیاده‌سازی‌کننده بتونن از بازخوردهاشون برای ارتقاء اپ و یا رفع خطاهای احتمالی استفاده کنن.چند تا از نسخه‌های بارگذاری‌شده اپ مثقال روی آی‌تونز کانکت⚠️ : یه نکته‌ای که توی روند بارگذاری این نسخه‌ها روی آی‌تونز کانکت هست، اینه که اگه ما بخوایم دو تا نسخه با شماره اصلی نسخه، و شماره ساخت یکسان رو بارگذاری کنیم، خود پنل خطا میده، و از این کار جلوگیری می‌کنه.مورد بعدی که بیشتر برای من جنبه شخصی داره، اینه که من معمولا دوست دارم همینطور که قسمت‌های مختلف یه اپ رو پیاده‌سازی می‌کنم، این شماره ساخت رو هم زیاد کنم! ? ولی خب این روند باید بصورت دستی انجام میشد، و یکم برای اذیت‌کننده میشد؛ هم می‌خواستم انجامش بدم، و هم رویه‌ش دم دستی نبود!با یه سرچ کوچیک، یه کدی پیاده کردم، که برای اینکار هست! کار این کد اینه که در هر بار خروجی گرفتن از اپ (یا در واقع Buildکردن پروژه)، میاد و مقدار شماره ساخت رو یک واحد افزایش میده. بهمین راحتی، بهمین خوشمزگی! ?کد مورد نظرمون اینه:buildNumber=$(/usr/libexec/PlistBuddy -c &quot;Print CFBundleVersion&quot; &quot;${PROJECT_DIR}/${INFOPLIST_FILE}&quot;)
buildNumber=$(($buildNumber + 1))
/usr/libexec/PlistBuddy -c &quot;Set :CFBundleVersion $buildNumber&quot; &quot;${PROJECT_DIR}/${INFOPLIST_FILE}&quot;کاری که این اسکریپت می‌کنه، در حقیقت اینه: میاد مقدار فعلی شماره ساخت رو از فایل مربوطه (که از نوع Property List هست) می‌خونهمقدارش رو یک واحد زیاد می‌کنه، ومقدار جدید رو داخل همون فایل ذخیره می‌کنه. همین!برای اطلاعات بیشتر، باید بگم این مقادیری که توی اسکریپت می‌بینین، مثل PROJECT_DIR و یا INFOPLIST_FILE، متغیرهایی هستن که خود ایکس کد باهاشون کار می‌کنه. اگه بازم اطلاعات بیشتری می‌خواین، می‌تونین از این لینک که از مستندات خود سایت اپل هست استفاده کنین.روش استفاده از اسکریپت افزایش خودکار شماره ساختتوی قسمتی که کلیات پروژه رو نشون میده، تارگت اصلی که خود اپ هست رو انتخاب کنیناز گزینه‌های بالا، گزینه Build Phases رو بزنینبا استفاده از علامتی که برای ایجاد یه اسکریپت جدید هست، یه گزینه جدید ایجاد کنینکد اسکریپت بالا رو توی قسمت مربوطه کپی کنینتمام! ?نمونه نهایی این روند میشه مثل عکس زیر:⚠️ توجه داشته باشین، زمانیکه از این اسکریپت استفاده می‌کنین، مقداری که برای قسمت Build Number تنظیم میشه، و یا خودتون بطور دستی بعدا تغییرش میدین، حتمن عددی باشه؛ تا اسکریپت بتونه بدرستی کار خودش رو انجام بده.از حالا به بعد، هر موقع که پروژه رو Build کنین، شماره ساخت، یک واحد اضافه میشه. ?? : برای فهم راحت‌تر و بهتر این اسکریپت‌ها، می‌تونین اسم مربوط به این اسکریپت رو هم تغییر بدینش. برای اینکار روی عنوانش دوباره کلیک کنین، و اسم دلخواه‌تون رو تایپ کنین.من بشخصه با این اسکریپت خیلی حال کردم! ?شمام اگه ازش خوش‌تون اومد، توی پروژه‌هاتون استفاده کنین.? منبع مطلب: این مطلب رو بر اساس این پست نوشتم.</description>
                <category>امید گل پرور</category>
                <author>امید گل پرور</author>
                <pubDate>Tue, 30 Jan 2018 23:36:48 +0330</pubDate>
            </item>
            </channel>
</rss>