مشاوره رایگان
دریافت لینک های دانلود دریافت پستی درب منزل مبلغ کل: تومان
جهت دریافت کد تخفیف به کانال تلگرام مراجعه و یا با پشتیبان آنلاین هماهنگ نمایید

مقدمه ای بر بلوک های Objective-C


در برنامه نویسی ، چیزی که یک توسعه دهنده خوب را از یک توسعه دهنده عالی متمایز می کند ، روشی است که هر کدام از آنها از ابزارهای برنامه نویسی پیشرفته ای که زبان مورد نظر در اختیار آنها قرار می دهد ، استفاده می نمایند. Objective-C ، زبان رسمی برای توسعه اپلیکیشن آیفون ، آیپد و Mac OS می باشد و یک زبان چند منظوره ، مرتبط با C و بسیار قدرتمندی است. توسعه دهندگان تازه کار ، در هنگام شروع کار با Objective-C ، موارد بسیاری را برای کاوش دارند. با این حال ، برنامه نویسان حرفه ای نیز همیشه با برخی چیزهای جدید برای یادگیری مواجه هستند ، چرا که این زبان از قابلیت های های برنامه نویسی بسیاری پشتیبانی می کند. یکی از این ویژگی ها ، توانایی کدنویسی با استفاده از بلوک ها (Block) می باشد.

بلوک ها ، کشف جدیدی در برنامه نویسی Objective-C نیستند. آنها در سایر زبان های برنامه نویسی نیز وجود دارند (مانند JavaScript) که با عناوین دیگری مانند ، Closure ها شناخته می شوند. در iOS ، بلوک ها اولین بار در ورژن 4.0 معرفی شدند و از آن زمان به شدت مورد توجه و استفاده قرار گرفتند. در نسخه های بعدی iOS ، اپل متدهای فریم ورک بسیاری را بازنویسی یا به روز رسانی نمود تا با بلوک ها مطابقت یابند ، و این طور به نظر می رسد که بلوک ها ، بخشی از مسیر آینده کدنویسی باشند. اما واقعاً بلوک ها چه چیزی هستند؟

خوب ، یک بلوک قابلیت self-contained دارد و به صورت کد مستقل می باشد ، و همیشه در داخل محدوده ساختار برنامه نویسی دیگری مانند بدنه یک متد وجود دارد. کدهای یک بلوک می توانند با دنیای خارج از آن تعامل داشته باشند ، اما چیزی که در داخل بلوک قرار دارد قابل رؤیت برای محدوده خارج از آن نیست. هم چنین ، بلوک ها می توانند مقادیر متغیرهای که خارج از بدنه آنها قرار دارند را با استفاده از یک روش خاص تغییر دهند (بعداً در مورد این موضوع مطالب بیشتری ارائه خواهیم کرد). بلوک ها دو ویژگی بزرگ دارند:

  1. بلوک ها می توانند در زمان دیگری اجرا شوند ، نه فقط الزاماً در زمانی که کد محدوده آنها در حال اجرا شدن هستند.
  2. کاربرد آنها در نهایت منجر به نوشتن کد بسیار تمیزتر و دقیق تر می شود ؛ زیرا می توانند به جای متدهای نماینده مورد استفاده قرار گیرند ، فقط در یک جا نوشته می شوند و در فایل های زیادی گسترش نمی یابند.

با توجه به ویژگی دوم ، بلوک ها می توانند راه حل خوبی برای ایجاد callback ها به جای نمایندگان فراهم کنند ، زیرا آنها به طور مستقیم در نقطه ای از کد که فراخوانی شده اند ، اعلام و پیاده سازی می شوند. با استفاده از بلوک ها ، نیازی به ایجاد سازگاری با پروتکل ها ، یا پیاده سازی متدهای نماینده نیست که منجر به کدنویسی بسیاری در داخل یک کلاس می شوند. با این حال ، بهترین کاربرد بلوک ها این است که ، رویه callback می تواند به طور مستقیم به هر متغیر موجود در محدوده ای که بلوک در آنجا تعریف شده است ، دسترسی داشته و استفاده نماید. بنابراین ، دیگر نیازی به انتقال اطلاعاتی مانند متدهای callback نیست. با این حال ، بلوک ها نمی توانند به طور کامل جایگزین نمایندگان شوند ، زیرا نمی توانند برای هر منظوری استفاده شوند. بهترین روش این است که ترکیبی از هر دو را داشته باشیم که می توانند با پیروی از برخی قوانین ساده و با استفاده از تجربه های به دست آمده در طول زمان ، حاصل شوند.

بلوک ها object هایی هستند که می توانند در ساختار داده های NSArray و NSDictionary ذخیره شده و هم چنین ، به متغیرها تخصیص داده شوند.

دو واقعیت وجود دارد که هر توسعه دهنده ای در مورد آنها اطمینان دارد ، حتی اگر درباره بلوک ها هیچ نظری نداشته باشد. اول این که ، هر کسی از بلوک ها استفاده نموده است ، حتی اگر از این موضوع اطلاع نداشته باشد. زیرا ، اپل بلوک ها را به طور ویژه به عنوان دستیارهای تکمیلی برای بسیاری از متدهای مهم و پر کاربرد قرار داده است. دوم این که ، خوشبختانه یا متأسفانه ، نیازی به داشتن دانش عمیقی در برنامه نویسی بلوک ها جهت استفاده از آنها مورد نیاز نیست ، کافی است که درکی از چگونگی عملکرد آنها وجود داشته باشد.

بلوک ها فقط یک ویژگی خارق العاده دارند ، و این همان شیوه ای است که نوشته می شوند. اگر با این مباحث ناآشنا هستید ، نگران نباشید ، زیرا بعد از چند روز استفاده و نوشتن بلوک ها ، در استفاده از آنها مانند هر چیز دیگری در Objective-C مهارت خواهید یافت.

در این آموزش ، ما دو هدف را دنبال خواهیم کرد: برای روشن شدن تمام مطالب ، از کدهای مربوطه استفاده خواهیم نمود، و بالاتر از همه برای نشان دادن این که چگونه می توانیم در عمل از بلوک ها استفاده نماییم ، از مثال های عملی استفاده خواهیم کرد تا یادگیری شما راحت تر صورت پذیرد. اگر تاکنون برنامه نویسی بلوک ها را انجام نداده اید ، پس از پایان این آموزش ، شروع به انجام این کار خواهید نمود.

پس به خواندن این مقاله ادامه دهید تا با مطالب جالب و جذابی آشنا شوید.

بازبینی اپ

اپلیکیشن آزمایشی که ما برای اهداف آموزشی خواهیم ساخت ، شامل چندین بخش است که مستقل از یکدیگر هستند. در واقع ، می توانیم یک اپلیکیشن  command-line پیاده سازی نماییم ، اما ، از آن جایی که می خواهیم برخی UI مرتبط با محتوا را نشان دهیم ، یک اپ بسیار ساده را خواهیم ساخت. قبل از همه ، قصد داریم کدهایی بنویسیم که پیام هایی را فقط در debugger نشان می دهند ، بدون این که هیچ رابط کاربری خاصی برای آنها بسازیم. از آن جایی که می خواهیم در کار ساخت اولین بلوک خود تمرکز نماییم ، لذا بخش های اپ شامل چندین مثال کوچک می باشد که در آنها فقط به نتایج برگشت داده شده توجه می کنیم. با این حال ، از آن جایی که قصد داربم برخی از task های مرتبط با view را انجام دهیم و می خواهیم که اپلیکیشن ما تعامل UI را فراهم نماید ، از این رو ، برخی از رابط های کاربری را نیز خواهیم ساخت. مهم تر از همه این است که هر بخش از اپ ما بر روی روش دیگری از استفاده از بلوک ها تمرکز خواهد کرد ، از این رو ، تکنیک های مفیدی در عمل نشان داده خواهند شد.

ایجاد اپ Demo

قبل از این که هر بحثی را شروع کنیم و وارد بخش کدنویسی شویم ، لازم است که یک پروژه آماده داشته باشیم. بنابراین ، بیایید ابتدا یک پروژه را بسازیم. Xcode را راه اندازی می کنیم و از پنجره Welcome گزینه create a new project را انتخاب می کنیم:

در اولین مرحله ، از بخش iOS و از دسته بندی Application گزینه Single View Application را انتخاب می کنیم.

روی کلید Next کلیک می کنیم. نام پروژه را تنظیم می کنیم . ما نام آن را BlockDemo قرار دادیم، اما شما در نامگذاری پروژه خود آزاد هستید و هر نامی را که ترجیح می دهید ، می توانید انتخاب نمایید. از منوی کشویی در بخش Devices مقدار iPhone را انتخاب می کنیم.

دوباره روی کلید Next کلیک می کنیم و دایرکتوری مقصد را انتخاب می نماییم. هنگامی که کار را انجام دادیم ، روی کلید Create کلیک می کنیم و اکنون ما آماده هستیم.

بلوک بندی اصلی

قبل از این که وارد بخش بلوک ها بشویم ، باید بگوییم که شما می توانید تمام کدهای ارائه شده در این بخش را در داخل متد viewDidLoad در فایل ViewController.m بنویسید ، در صورتی که تمایل دارید خودتان همه چیز را امتحان کنید ، پس بیایید باهم شروع کنیم!

اعلان یک بلوک به صورت الگوی syntax زیر است:

ReturnType (^blockName)(Parameters)

اعلان فوق بسیار شبیه به اعلان تابع در C می باشد ، با یک استثناء بزرگ: نماد (^)caret ، که نشان می دهد شیء اعلان شده ، یک بلوک است. بیایید همه چیز را تک به تک بررسی کنیم:

  • ReturnType : هر نوع داده Objective-C را پشتیبانی می کند ، یا اگر بلوک چیزی را برنگرداند ، از حالت void پشتیبانی می کند.
  • ^blockName : همیشه باید به خاطر داشته باشیم که نام بلوک با نماد پسوند ^ همراه است. نام بلوک می تواند هر رشته ای که می خواهیم ، باشد ، همانند نام سایر متغیرها یا متدها. نام بلوک و نماد ^ باید در داخل پرانتز () قرار گیرند.
  • Parameters : لیستی از پارامترهایی که می توانیم به بلوک پاس دهیم ، همانند حالتی که متدها را اعلان می کنیم. با این حال ، باید این نکته مهم را به خاطر بسپاریم که وقتی هیچ پارامتری را به بلوک پاس نمی دهیم ، همیشه باید کلمه کلیدی void تنظیم شود. هم چنین ، لیست آرگومان ها باید در داخل پارانتز قرار داده شوند.

مطالب فوق تمام مواردی هستند که در مورد اعلان بلوک ها نیاز داریم بدانیم. در اینجا چند مثال را می آوریم:

int (^firstBlock)(NSString *param1, int param2);
 
void (^showName)(NSString *myName);
 
NSDate *(^whatDayIsIt)(void);
 
void (^allVoid)(void);
 
NSString *(^composeName)(NSString *firstName, NSString *lastName);

استفاده از نماد ^  و تمام این پارانتزها ممکن است گیج کننده به نظر بیایند ، اما نگران نباشید. ما باید از بلوک ها استفاده کنیم و نباید نماد ^ را فراموش نماییم.

یک کاراکتر ویژه که اعلان بلوک با آن همراه است ، نام پارامترها است که می توانند حذف شوند ، و فقط نوع پارامترها نگه داشته شوند. در واقع ، افزودن نام پارامترها به اعلان تنها به توسعه دهندگان کمک می کنند که آنها را به خاطر بسپارند ، و چیزی را به کامپایلر ارائه نمی دهند. از این رو ، اعلان های فوق می توانند دوباره بدون نام پارامترها بازنویسی شوند:

int (^firstBlock)(NSString *, int);
 
void (^showName)(NSString *);
 
NSDate *(^whatDayIsIt)(void);
 
void (^allVoid)(void);
 
NSString *(^composeName)(NSString *, NSString *);

استفاده کردن یا نکردن از نام پارامترها در کل به ما بستگی دارد. استفاده کردن یا حذف نمودن آنها اشتباه تلقی نمی شود. معمولاً ، توسعه دهندگان حرفه ای ، با بلوک ها آشنا هستند و نام پارامترها را نمی نویسند و فقط نوع آنها را می نویسند ، اما در مورد تازه کارها ، نوشتن نام پارامترها به آنها کمک زیادی می کند.

اکنون بیایید بر روی تعریف بلوک تمرکز نماییم. در اینجا الگوی تعریف بلوک آورده شده است:

^(Parameters){
 
... block body ...
 
return ReturnValue (or nothing if the block return type is void)
};

همان که از تعریف فوق دیده می شود ، نام بلوک در اینجا آورده نشده است. در تعریف بلوک ، نام پارامترها اجباری هستند ، برخلاف اعلان بلوک که نام پارامترها اختیاری می باشد. به ویژه باید توجه شود که پس از بستن بدنه بلوک ، سیمکالن (;) اضافه شده باشد ، زیرا کل بلوک به عنوان یک متغیر در نظر گرفته می شود. نگران نباشید ، حتی اگر آن را فراموش نمایید ، کامپایلر عدم وجود آن را یادآوری می نماید.

در اینجا یک مثال ساده از تعریف بلوک آورده شده است:

    ^(int a, int b){
        int result = a * b;
        return result;
    };

البته ، هرگز از بلوک ها به سادگی مثال فوق استفاده نمی شود. در بیشترین احتمال ، کاربرد تعریف بلوک به این صورت است که نتیجه (result) تعریف بلوک به یک متغیر اختصاص داده می شود ، یا این که بلوک را با استفاده از آن به عنوان یک handler تکمیلی بر اساس فراخوانی متد تعریف خواهیم کرد.

اکنون ، بیاید در دو مثال زیر نحوه تخصیص نتایج بلوک را به متغییر بلوک مشاهده کنیم:

int (^howMany)(int, int) = ^(int a, int b){
    return a + b;
};

در این مثال ، نام پارامترها در اعلان ، حذف شده است ، اما ، آنها به طور اجباری در تعریف بلوک وجود دارند. یک بار دیگر ، استفاده از نما ^ و ; برای بستن بدنه بلوک را تأکید می کنیم.

یک مثال دیگر:

void (^justAMessage)(NSString *) = ^(NSString *message){
   NSLog(@"%@", message);
};

همان طور که در مثال فوق می بینیم ، نوع برگشتی بلوک ، void می باشد ، بنابراین هیچ دستور بازگشتی نداریم.

اجازه دهید که این موضوع را روشن کنیم که اعلان (declaration) و تعریف (definition) به صورت همزمان ضروری نیستند. برای مثال :

    // Declare a block variable.
    void (^xyz)(void);
    
    // Some other code...
    
    // Define the block.
    xyz = ^(void){
        NSLog(@"What's up, Doc?");
    };

حتی بیشتر ، یک بلوک می تواند به عنوان یک متغیر عضو کلاس تعریف شود ، درست همانند هر متغیر عضو دیگری. برای مثال ، در بخش خصوصی (private) رابط می توانیم بنویسیم:

@interface ViewController ()
@property (nonatomic, strong) NSString *(^blockAsAMemberVar)(void);
@end

و سپس داخل viewDidLoad  کد زیر را اضافه می نماییم:

    _blockAsAMemberVar = ^(void){
        return @"This block is declared as a member variable!";
    };

کار سختی نیست ، موافق هستید؟ فقط باید همیشه مطمئن شویم که پارامترها را در اعلان بلوک به همان ترتیبی بنویسیم که از همان ترتیب و همان نوع در تعریف بلوک استفاده می نماییم.

به طور خلاصه باید بگوییم که ، تاکنون ما نحوه اعلان و نحوه تعریف بلوک را بیان کردیم و دو قانون در مورد هر کدام ذکر کردیم. با این حال ، چیزی که هنوز نشان نداده ایم ، نحوه فراخوانی بلوک ها می باشد ، فقط اعلان و تعریف ساده بلوک ها نمی تواند هیچ معنایی داشته باشد.

یک متغیر بلوک درست مانند تابع C ، با استفاده از نام آن و فراهم نمودن آرگومان های موردنیاز فراخوانی می شود. در اینجا ، برای شفاف سازی موضوع ، یک مثال آورده شده است:

    int (^howMany)(int, int) = ^(int a, int b){
        return a + b;
    };
    
    NSLog(@"%d", howmany(5, 10));
 
    // Output: 15

بیایید یک مثال دیگر را ببینیم:

   NSDate *(^today)(void);
    
    today = ^(void){
        return [NSDate date];
    };
    
    NSLog(@"%@", today());
 
    // Outputs the today's date.

امیدواریم این مثال شما را سردرگم نسازد:

    float results = ^(float value1, float value2, float value3){
        return value1 * value2 * value3;
    } (1.2, 3.4, 5.6);
 
    NSLog(@"%f", results);
 
    // Output: 22.848001

این مثال یک رویکرد مستقیم است ، که با استقاده از آن بلوک را تعریف می نماییم ، مقادیر پارامترها را پاس می دهیم و نتایج را به یک متغیر تخصیص می دهیم.

در مثال آخر ، از متغیر موجود در تعریف بلوک استفاده می نماییم:

    int factor = 5;
    int (^newResult)(void) = ^(void){
        return factor * 10;
    };
    
    NSLog(@"%d", newResult());
 
    // Output: 50

در این مرحله ، باید درک پایه ای از اصول نوشتن و استفاده از بلوک ها را کسب نموده باشید. اکنون وقت آن است که کمی به جلو حرکت کرده و با برخی از موضوعات پیشرفته تر آشنا شویم ، که قطعاً در مسیر برنامه نویسی به آنها نیاز خواهیم داشت.

نوع ذخیره سازی بلوک

کد موجود در بلوک می تواند به یک متغیر دسترسی داشته باشد که متعلق به دامنه متدی است که بلوک در آن تعریف شده است. اما به طور پیش فرض ، این دسترسی از نوع فقط خواندنی می باشد. این بدان معنا است که کد مربوط به بلوک نمی تواند مقدار متغیر را از دنیای بیرونی تغییر دهد. این محدودیت ، یک واقعیت مفید برای حفاظت ما از هر گونه تغییرات ناخواسته می باشد. با این حال ، توانای برای تخصیص دادن مقادیر جدید در چنین متغیرهایی ، در بسیاری از مواقع ضروری می باشد.

قبل از این که نشان دهیم به چه نحوه می توانیم این کار را انجام دهیم ، برای ساده نگه داشتن مطالب ، بیایید یک متد خصوصی ایجاد نماییم و از آن برای نشان دادن عملکرد فوق استفاده نماییم. پس ، ابتدا بیایید چند کار ساده انجام دهیم ، به بخش private از رابط رفته و اعلان متد جدید را اضافه می کنیم:

@interface ViewController ()
...
-(void)testBlockStorageType;
@end

سپس ، در داخل متد viewDidLoad  ، آن را فراخوانی می نماییم:

- (void)viewDidLoad
{
    [super viewDidLoad];
    ...
    [self testBlockStorageType];
}

اکنون می توانیم روی کار پیاده سازی تمرکز کنیم. برای شروع ، پیاده سازی آن را از طریق افزودن کد زیر انجام می دهیم:

در این قطعه کد ، متغیر someValue  را داریم که متعلق به متد است و داخل بلوک myOperation  سعی می کنیم مقدار آن را تغییر دهیم. متوجه خواهیم شد که Xcode یک خطا را نشان می دهد ، خط بعدی را داخل بلوک برجسته می کند...

someValue += 5;

و پیام “Variable is not assignable“ را با برخی از اطلاعات اضافی نشان می دهد. Xcode اجازه ادامه کار را به ما نمی دهد تا زمانی که این وضعیت را مدیریت نماییم.

خوشبخانه ، Objective-C یک نوع modifier خاص ذخیره سازی به نام __block را فراهم می کند که در هنگام اعلان متغیره مورد استفاده قرار می گیرد. این modifier این امکان را می دهد که متغیر قابل تغییر شود ؛ به طوری که بلوک ها بتوانند دسترسی نوشتن در آن را داشته باشند. در مثال ما ، مشکل ما یعنی این خط کد:

int someValue = 10;

به سادگی می تواند با این خط کد حل شود:

__block int someValue = 10;

اگر این خط را تست نماییم ، خطای Xcode از بین می رود ، و نتیجه مورد انتظار را بر روی debugger خواهیم دید (که خط 25 است).

از طریق این مثال بسیار ساده ، استفاده از __block specifier به اندازه کافی روشن می شود و می توان کاربرد آن را به خوبی درک نمود. به عنوان نکته نهایی ، در هنگام تایپ ، دو نماد underscore (__) قبل از کلمه کلیدی block نباید فراموش نشود.

بلوک ها به عنوان Handler های تکمیلی

بسیاری از توسعه دهندگان وقتی در مورد بلوک ها فکر می کنند ، در واقع در مورد completion handlers فکر می کنند و یک دلیل خوب برای آن دارند. زیرا بلوک ها در بسیاری از متدهای فریم ورک به طور گسترده به عنوان completion handlers مورد استفاده قرار می گیرند. به همین دلیل است که توسعه دهندگان iOS ، حتی تازه کارها نیز به احتمال زیاد با completion handler ها کار کرده اند ، اما ، قبل از این که بیشتر پیش برویم ، ابتدا باید به این سؤال پاسخ دهیم که ، completion handler چه چیزی است؟

یک completion handler روش (یا تکنیکی) برای پیاده سازی عملکرد callback با استفاده از بلوک ها می باشد. در مقدمه این آموزش ، اشاره کردیم که بلوک ها می توانند به جای نماینده مورد استفاده قرار گیرند و به عنوان callback ها عمل نمایند، این کار می تواند از طریق completion handler ها صورت پذیرد.

یک completion handler چیزی بیش از یک بلوک ساده پاس داده شده به عنوان یک پارامتر به یک متدی که نیاز دارد یک عمل callback را در زمانی دیگر انجام دهد ، نیست. وقتی که این زمان فرا می رسد ، بلوک به سادگی فراخوانی می شود. علاوه بر این ، تعریف بلوک قبل از فراخواتی متد انجام می شود ، از این رو ، هرگونه action که باید پس از انجام callback انجام شود ، می تواند به صورت محلی پیاده سازی گردد.

نکته مهمی که قبل از ادامه کار نباید آن را فراموش کنیم ، این است که completion handler همیشه باید آخرین پارامتر در یک متد باشد. یک متد می تواند آرگومان های بسیاری به همان اندازه که می خواهیم ، داشته باشد ، اما completion handler به عنوان آخرین آرگومان در لیست پارامترها باید باشد.

در اینجا ، پارامتر اعلان  مربوط به متدی که حاوی یک completion handler برای ایجاد callback ها است ، آورده شده است:

-(returnType)methodNameWithParams:(parameterType)parameterName ...<more params>... andCompletionHandler:(void(^)(<any block params>))completionHandler;

پیاده سازی آن به صورت زیر است:

-(returnType)methodNameWithParams:(parameterType)parameterName ...<more params>... andCompletionHandler:(void(^)(<any block params>))completionHandler{
    ...
    ...
 
    // When the callback should happen:
    completionHandler(<any required parameters>);
}

بلوک  completion handler همیشه زمانی که متد فراخوانی می شود ، تعریف می شود:

[self methodNameWithParams:parameter1 ...<more params>... andCompletionHandler:^(<any block params>){
    // The completion handler code is added here after the method has finished execution and has made a callback.
}];

دو مثال معمول از  completion handler ها از متدهای فریم ورک عبارتند از:

  1. هنگام نمایش یک  modal view controller ، اگر بخواهیم چیزی را که بعد از view controller نمایش داده شده است را هندل نماییم:
    [self presentViewController:viewController animated:YES completion:^{
        NSLog(@"View Controller was presented...");
        
        // Other code related to view controller presentation...
    }];

2- هنگامی اجرای انیمیشن های UIView

    [UIView animateWithDuration:0.5
                     animations:^{
                         // Animation-related code here...
                         [self.view setAlpha:0.5];
                     }
                     completion:^(BOOL finished) {
                         // Any completion handler related code here...
                         
                         NSLog(@"Animation is over.");
                     }];

بیایید یک مثال ساده را که نحوه ایجاد یک متد با completion handler ، نحوه فراخوانی آن و نحوه کار با completion handler را نشان می دهد ، با هم بررسی نماییم. برای ساده نگه داشتن مطالب ،  ما یک متد را پیاده سازی خواهیم کرد که دو عدد صحیح را جمع می زند ، و به جای بازگرداندن نتیجه به caller ، ما آن را به back با استفاده از completion handler ارسال خواهیم کرد. البته ، در دنیای واقعی ، هرگز با چنین متد ساده ای با استفاده از completion handler مواجه نخواهیم شد ، اما این متد می تواند کمک بسیاری نماید تا ایده completion handler به طور کامل به شما انتقال یابد. پس بیایید کار را شروع کنیم.

در فایل ViewController.m ، به بخش private از رابط می رویم و اعلان متد زیر را انجام می دهیم:

@interface ViewController ()
...
 
-(void)addNumber:(int)number1 withNumber:(int)number2 andCompletionHandler:(void (^)(int result))completionHandler;
 
@end

همان طور که در کد فوق مشاهده می شود ، ما یک متد را با سه پارامتر اعلام می کنیم. دو پارامتر اول ، اعدادی هستند که می خواهیم جمع بزنیم ، و پارامتر آخر completion handler است. می توانیم هر نامی را برای پارامتر completion handler انتخاب نماییم. همان که مشاهده می شود ، اعلان بلوک در completion handler فقط حاوی یک پارامتر است ، و آن نتیجه ای است که ما می خواهیم به caller متد ارسال نماییم. در موارد واقعی ، ممکن است پارامترهای بسیاری را در صورت تمایل بخواهیم اضافه نماییم ، اما در این مورد چیزی که ما ترجیح می دهیم این است. بیایید به سراغ کار پیاده سازی برویم که واقعاً ساده است:

-(void)addNumber:(int)number1 withNumber:(int)number2 andCompletionHandler:(void (^)(int result))completionHandler{
    int result = number1 + number2;
    completionHandler(result);
}

کار سختی نیست. ما فقط دو عدد را جمع کردیم و completion handler را فراخوانی کردیم ، پارامتر مورد انتظار و حاصل جمع را پاس دادیم.

اکنون بیایید متد viewDidLoad  را مطابق کد زیر فراخوانی نماییم:

- (void)viewDidLoad
{
    ...
 
    [self addNumber:5 withNumber:7 andCompletionHandler:^(int result) {
        // We just log the result, no need to do anything else.
        NSLog(@"The result is %d", result);
    }];
}

هنگام فراخوانی متد ، ما مقادیر 5 و 7 را به عنوان پارامتر پاس می دهیم و یک بلوک completion handler را در اینجا تعریف می کنیم. واضح است که هندل کردن هر گونه action مربوط به callback می تواند در اینجا بسیار مفید باشد ، مانند ایجاد کردن پروتکل ها ، متدهای نماینده و غیره ، که در همه جا پراکنده هستند. در هر صورت ، این فقط یک مثال است ، در اینجا نیازی به handling خاصی نداریم ، بنابراین ، ما فقط حاصل جمع را log می کنیم.

سه قطعه کد آخری مربوط به خلاصه روشی است که ما می توانیم با completion handler ها کار کنیم. اگر در انجام این کار تازه کار هستید ، نگران نباشید. این فقط یک عادت کدنویسی در چنین شیوه ای می باشد. Xcode همه چیز را برای ما آسان تر می کند و درست وقتی که شروع به نوشتن فراخوانی متد می کنیم ، چیزی را که در ویرایشگر تایپ می کنیم ، پیشنهاد می دهد ، مطابق تصویر زیر:

 

پس از وارد کردن مقادیر عددی و انتقال دادن آرگومان completion handler ، از طریق پاس دادن کلید Return در صفحه کلید Xcode ، بدنه بلوک را مطابق تصویر زیر ایجاد می نماید:

ما باید callback را هندل نماییم و البته ، نباید سمیکالن انتهایی را فراموش نماییم.

پس از این که کار با completion handler را از طریق مثال بسیار ساده فوق نشان دادیم ، اکنون زمان آن است که کارهای پیشرفته تری را انجام دهیم و استفاده واقعی از آن را که در اپلیکیشن واقعی به عنوان یک ابزار مورد استفاده ، نشان دهیم.

 

Completion Handler : یک مثال عملی

کار را با شرح اهداف خود آغاز می نماییم و سپس وارد مرحله پیاده سازی خواهیم شد. پس ، کاری که قصد داریم در اینجا انجام دهیم ، ایجاد یک کلاس سفارشی برای ساخت یک شیء UIActionSheet  با استفاده از  completion handler می باشد ، بدون این که از هیچ متد نماینده ای استفاده کنیم. اگر تا بحال با action sheet ها کار کرده باشید ، می دانید که برای استفاده از آنها ، باید کلاس خود را مطابق با پروتکل UIActionSheetDelegate بسازیم ، و سپس حداقل یک متد نماینده را اجرا نماییم ، که معمولاً متد actionSheet:clickedButtonAtIndex: می باشد. از این طریق ، خواهیم فهمید که کلید ضربه شده توسط کاربر کدام کلید است. رویکرد نرمال و معمول به این صورت است که باید کدی را در محل های مختلفی بنویسیم ، اما اگر بتوانیم پاسخ کاربر به گزینه های ارائه شده از طریق action sheet را در محل فراخوانی آن هندل نماییم ، و همه آنها را با همدیگر داشته باشیم ، عالی نیست؟ این دقیقاً کاری است که ما می خواهیم انجام دهیم!

پس از داشتن کلاس سفارشی آماده ، می توانیم آن را به عنوان تکه کد مفید برای پروژه های دیگر استفاده کنیم. به سادگی ، با استفاده از یک completion handler مدیریت کردن انتخاب کاربر در یک action sheet بسیار آسان تر و جذاب تر از آن چیزی می باشد که می توانیم تصور کنیم. پس بیایید شروع کنیم.

قبل از همه ، بیایید بک فایل کلاس جدید را بسازیم. سریع ترین راه برای انجام این کار ، این است که ترکیب کلیدهای &#8984-N را در صفحه کلید فشار دهیم یا از منو قسمت File > New > File … را استفاده نماییم.

در راهنمایی که ظاهر می شود ، در دسته بندی Cocoa Touch ، در بخش iOS  ، گزینه Objective-C را انتخاب می کنیم:

برای وارد شدن به بخش بعد ، کلید Next را کلیک می کنیم. همان طور که در شکل زیر نشان داده شده است ، در فیلد Subclass of مطمئن می شویم که مقدار NSObject  انتخاب شده باشدو در فیلد Class ، مقدار CustomActionSheet را تایپ می کنیم.

یکبار دیگر روی کلید Next کلیک کرده و در صفحه بعدی که ظاهر می شود ، برای اتمام کار ، روی کلید Create کلیک می کنیم. اکنون باید Project Navigator را با این دو فایل جدید ببینیم:

در کلاس سفارشی ما ، می خواهیم که تمام action sheet handling متداول و موردنیاز را بسازیم. بدین معنا که می خواهیم کلاس را مطابق با پروتکل UIActionSheet  ساخته و متد نماینده actionSheet:clickedButtonAtIndex:  و هر چیز دیگری را که ممکن است لازم داشته باشیم ، پیاده سازی نماییم. اما مهم ترین چیز این است که ما همه این کارها را فقط یک بار انجام خواهیم داد. بعد از این ، دوباره با این کارها خودمان را به زحمت نمی اندازیم ، زیرا به سادگی از completion handler برای مدیریت کردن هر callback ایجاد شده توسط یک شیء action sheet ، استفاده می کنیم. به این فکر نکنید که تمام این موارد برای شما گیج کننده هستند. در انتهای این بخش ، شما  همه چیز را به خوبی در مورد آنها خواهید فهمید و یک ابزار مفید را در اختیار خواهید گرفت.

پس ، فایل CustomActionSheet.h  را باز کرده و آن را مطابق با کد زیر با پروتکل UIActionSheet  تطبیق می دهیم:

@interface CustomActionSheet : NSObject 

در ادامه ، متد init سفارشی زیر را اعلان می کنیم ، از این رو ، کلاس ما می تواند با استفاده از پارامترهای مشابه که شیء action sheet  از طریق مقداردهی اولیه دریافت می کند ، مقداردهی اولیه شود:

@interface CustomActionSheet : NSObject 
 
-(id)initWithTitle:(NSString *)title delegate:(id)delegate cancelButtonTitle:(NSString *)cancelButtonTitle destructiveButtonTitle:(NSString *)destructiveButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, ...;
 
@end

ممکن است این کار کمی عجیب به نظر بیاید ، اما این کار شبیه به متد init در action sheet می باشد. قبل از این که ادامه دهیم ، اجازه دهید ، یکی از متدهای مهم را اعلان نماییم ، همان متدی که ما را قادر می سازد action sheet را در view نشان دهیم:

@interface CustomActionSheet : NSObject 
...
 
-(void)showInView:(UIView *)view withCompletionHandler:(void(^)(NSString *buttonTitle, NSInteger buttonIndex))handler;
 
@end

به طور معمول ، در هنگام فراخوانی متد showInView:  ، بخش action sheet در view ای که پارامتر آن را تنظیم می کنیم ، نمایان می شود. در مورد مثال ما ، این متد را با همان نام اعلام می کنیم تا آشنا به نظر بیاید ، اما مورد جدید و عالی completion handler است که در انتهای متد می آید. همان طور که مشاهده می شود ، دو پارامتر را در بلوک تعیین می کنیم: یک پارامتر NSString و یک پارامتر NSInteger  ، که به ترتیب عنوان و ایندکس کلید ضربه زده شده را نشان می دهند. با استفاده از این متد ، دیگر لازم نیست که در هنگام نیاز به یک action sheet ، متد نماینده ای را دوباره بنویسیم ، زیرا اکنون ما completion handler را داریم. عالی هست ، موافق هستید؟

اکنون ، بیایید به فایل CustomActionSheet.m  برویم. به بخش private از کلاس می رویم (اگر آنجا نباشد ، آن را مطابق کد زیر اضافه می کنیم) ، و دو اعلان object را به صورت زیر اضافه می کنیم:

@interface CustomActionSheet()
 
@property (nonatomic, strong) UIActionSheet *actionSheet;
 
@property (nonatomic, strong) void(^completionHandler)(NSString *, NSInteger);
 
@end

خط اول ، یک شیء action sheet است که از طریق کلاس ما مورد استفاده قرار می گیرد. دومین خط ، completion handler را نگه می دارد که به عنوان پارامتر ، برای متد قبلی فراهم شده است ، زیرا نیاز داریم که آن را بعد از این که اجرای متد پایان یافت ، فراخوانی نماییم. باید به این دو نکته توجه نماییم: نامی که برای بلوک تعیین می کنیم و پارامترهایی که از نوع مشابه هستند و به همان ترتیبی هستند که در متد completion handler می باشند. هم چنین ، همان طور که مشاهده می شود ، این بلوک همانند هر خصیصه دیگری اعلام شده است. فراموش نکنیم که ، همان طور که در بخش مقدمه گفته ایم ، یک بلوک یک شیئی است که بعد از همه تعریف می شود.

اکنون ، بیایید روی مقداردهی اولیه تمرکز نماییم. آن چه که ما انجام می دهیم ، این است که ابتدا شیء actionSheet را که قبلاً اعلام نموده ایم ، مقداردهی اولیه کنیم. در قطعه کد زیر ، برخی کدهایی وجود دارند که ممکن است عجیب به نظر بیایند ، ممکن است که بسیاری از شما آنها را برای اولین بار دیده باشید. با این وجود ، نگاهی به آنها خواهیم انداخت و در مورد آنها بحث خواهیم کرد.

-(id)initWithTitle:(NSString *)title delegate:(id)delegate cancelButtonTitle:(NSString *)cancelButtonTitle destructiveButtonTitle:(NSString *)destructiveButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, ...  {
    
    self = [super init];
    if (self) {
        _actionSheet = [[UIActionSheet alloc] initWithTitle:title
                                                   delegate:self
                                          cancelButtonTitle:nil
                                     destructiveButtonTitle:destructiveButtonTitle
                                          otherButtonTitles:nil];
        
        va_list arguments;
        va_start(arguments, otherButtonTitles);
        NSString *currentButtonTitle = otherButtonTitles;
        while (currentButtonTitle != nil) {
            [_actionSheet addButtonWithTitle:currentButtonTitle];
            currentButtonTitle = va_arg(arguments, NSString *);
        }
        va_end(arguments);
        
        [_actionSheet addButtonWithTitle:cancelButtonTitle];
        [_actionSheet setCancelButtonIndex:_actionSheet.numberOfButtons - 1];
        
    }
    
    return self;
}

قبل از همه ، مقداردهی اولیه با استفاده از کد زیر انجام می شود:

_actionSheet = [[UIActionSheet alloc] initWithTitle:title
                                                   delegate:self
                                          cancelButtonTitle:nil
                                     destructiveButtonTitle:destructiveButtonTitle
                                          otherButtonTitles:nil];

با این کد شیء action sheet مقداردهی اولیه می شود ، اما باید توجه شود که ما کلید cancel  و اشیاء button titles دیگری برای آن فراهم ننمودیم ، در عوض ، ما مقادیر Nil را پاس می دهیم. این کار به طور هدفمند انجام می شود ، زیرا شیء otherButtonTitles parameter پاس داده شده در متد init ، در واقعی لیستی از مقادیر می باشد ، و نیاز است که به طور خاصی تحت بررسی قرار گیرند. هم چنین ، کلید cancel باید آخرین کلید اضافه شده باشد. بنابراین ، ما آن را نیز nil می کنیم.

این چیزی است که بسیاری از شما آن را برای اولین بار می بینید:

va_list arguments;
va_start(arguments, otherButtonTitles);
NSString *currentButtonTitle = otherButtonTitles;
while (currentButtonTitle != nil) {
    [_actionSheet addButtonWithTitle:currentButtonTitle];
    currentButtonTitle = va_arg(arguments, NSString *);
}
va_end(arguments);

تمام عناوین کلیدها در متد init در فرم یک رشته nil-terminated داده شده اند ، که در واقع لیستی از رشته ها می باشند ، و به این معنی است که تعداد مقادیر موجود در آن ممکن است متفاوت باشد. وظیفه ما این است که مقادیر رشته را یک به یک به دست آوریم ، تا زمانی که مقدار nil را پیدا کنیم و این کار دقیقاً اینجا اتفاق می افتد. خلاصه ای از اشاره گر های va_XXX  و توابع عبارتند از:

  • va-list : این یک اشاره گری برای محتوای یک لیست می باشد که شامل تعداد متغیری از اشیاء (که معمولاً آرگومان نامیده می شود) می باشد.
  • va_start : اشاره گری است که اشاره گر va_list را با نشان دادن آن به عنوان اولین آرگومان از لیست ، مقداردهی می کند.
  • va­_arg : شیء بعدی از لیست را دریافت می کند ( در مثال ما ، عنوان کلید بعدی می باشد). دومین آرگومان همیشه نوع آرگومان می باشد ، زیرا این تابع نیاز دارد ، بداند که چند بایت باید استخراج شود.
  • va_end : این اشاره گر حافظه اختصاص داده شده و موردنیاز برای دسترسی به لیست و استخراج تمام آرگومان ها را آزاد می کند.

باید توجه شود که اینها توابع C هستند نه Objective-C. در هر صورت ، مهم است که بتوانیم تمام عناوین کلیدها را تک به تک با استفاده از دستور زیر اضافه نماییم:

[_actionSheet addButtonWithTitle:currentButtonTitle];

بعدی از این که تمام کلیدها اضافه شدند ، ما نباید کلید cancel را فراموش کنیم. بنابراین ، با این دو خط کد:

[_actionSheet addButtonWithTitle:cancelButtonTitle];
[_actionSheet setCancelButtonIndex:_actionSheet.numberOfButtons - 1];

افزودن دو action sheet را نیز مدیریت می نماییم. دومین خط ، مهم تر است ، زیرا با آن ، به action sheet اعلام می کنیم که این کلید cancel است و این همان مدیریت نمایش جداگانه کلید cancel از سایر کلیدها می باشد.

باید اقرار کنیم که مواردی که در اینجا مطرح کرده ایم ، موارد خیلی ساده ای نیستند ، اما قطعاً برای بسیاری از شما یک درس است و علاوه بر این ، این تنها راه برای دسترسی داشتن به تمام عناوین کلیدها می باشد.ما به سادگی پارامتر otherButtonTitles را برای مقداردهی اولیه action sheet فراهم کرده ایم. اما برای کسانی که فقط می خواهند پاسخ ها را ببینند ، action sheet فقط عنوان اولین کلید را نشان می دهد ، و با توجه به این که otherButtonTitles به عنوان یک شیء واحد است ، نه لیستی از آرگومان ها ، لذا از بقیه عنوان کلیدها صرف نظر می کند.

امیدواریم که مفهوم فوق را متوجه شده باشد ، بیایید پیاده سازی متد showInView:withCompletionHandler:  را انجام دهیم.

-(void)showInView:(UIView *)view withCompletionHandler:(void (^)(NSString *, int))handler{
    _completionHandler = handler;
    
    [_actionSheet showInView:view];
}

تنها نکته قابل توجه در اینجا این است که متغیر عضو کلاس completionHandler که به شیء handler block تخصیص می دهیم ، به عنوان پارامتر به متد پاس داده می شود. به این ترتیب ، حتی بعد از خروج از متد ، ما یک ارجاع به آن را نگه می داریم. دستور دوم یک دستور شناخته شده است و اجازه می دهد که action sheet در view خاصی نمایان شود.

اکنون ، اگر کلاس سفارشی را تست نماییم ، ما قادر خواهیم بود که یک action sheet  را در صفحه نمایش بسازیم. با این حال ، نمی توانیم با آن تعامل برقرار نماییم ، زیرا هنوز ، هیچ متد نماینده ای پیاده سازی نکرده ایم. پس ، بیایید یک متد نماینده را اضافه کنیم:

-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
    NSString *buttonTitle = [_actionSheet buttonTitleAtIndex:buttonIndex];
    
    _completionHandler(buttonTitle, buttonIndex);
}

اینجا دو action اجرا شده است: در اولی ، Title کلید ضربه زده شده به متغیر NSString اختصاص داده می شود و سپس چیزی که مدنظر ما است ، اتفاق می افتد ، completion handler فراخوانی می شود. بر اساس این فراخوانی ، ما دو پارامتر را تعیین می کنیم که در یک ترتیب مشخصی هستند. اولی مقدار رشته عنوان کلید ، و دومی مقدار صحیح ایندکس کلید می باشد. دستور دوم در واقع باعث انجام callback می شود و آن وظیفه ما است که مقدار برگشت داده شده در تعریف بلوک (در حلقه while) را مدیریت کنیم.

کلاس سفارشی ما آماده است! اکنون ما می توانیم یک action sheet را نمایش دهیم و رابط کاربری را به سادگی با استفاده از یک بلوک از completion handler هندل نماییم ، completion handler فقط درست در جایی که action sheet ظاهر می شود ، فراخوانی خواهد شد. اما قبل از این که ما این کار را انجام دهیم ، اجازه دهید یک UIButton برای view خود اضافه نماییم که منجر به این action خواهد شد.

ابتدا ، به فایل  ViewController.h رفته و متد IBAction  زیر را اعلام می کنیم:

@interface ViewController : UIViewController
 
- (IBAction)showActionSheet:(id)sender;
 
@end

اکنون ، روی فایل Main.storyboard کلیک کرده و از Objects Library یک UIButton را به convas اضافه می کنیم. مقادیر زیر را برای خصیصه های مربوطه تنظیم می کنیم:

  • Frame : X=95 ، Y=80 ، Width=131 ، Height=30
  • Title : Show Action Sheet

در ادامه با IBAction که قبلاً برای شیء button اعلام نموده ایم ، اتصال برقرار می کنیم و اکنون آماده هستیم. وارد جزئیات مربوط به نحوه ایجاد چنین اتصالی نمی شویم ، زیرا اگر درباره بلوک ها مطالعه نمایید ، برخی از موضوعات اصلی برای شما روشن تر خواهد شد ، همانند خصیصه های برقرار اتصال IBOutlet و متدهای IBAction.

در هر صورت ، رابط کاربری ما (که خیلی ساده است) باید مطابق تصویر زیر باشد:

پیش از این که وارد بخش پیاده سازی متد IBAction شویم ، دو کار باقی مانده است. فایل ViewController.m را باز کرده و کلاس سفارشی را که در فایل بالا ایجاد کرده ایم ، import می نماییم:

#import "CustomActionSheet.h"

سپس ، در بخش private از کلاس ، یک شیء CustomActionSheet را اعلام می کنیم:

@interface ViewController ()
...
 
@property (nonatomic, strong) CustomActionSheet *customActionSheet;
@end

در متد showActionSheet: IBAction ، مقداردهی اولیه شیء CustomActionSheet را انجام می دهیم. پارامترهایی را که تنظیم خواهیم کرد ، به شرح ذیل هستند:

- (IBAction)showActionSheet:(id)sender {
    _customActionSheet = [[CustomActionSheet alloc] initWithTitle:@"AppCoda"
                                                                       delegate:nil
                                                              cancelButtonTitle:@"Cancel"
                                                         destructiveButtonTitle:nil
                                                              otherButtonTitles:@"Option 1", @"Option 2", @"Option 3", nil];
}

همان طور که مشاهده می شود ، این کار درست شبیه به مقداردهی اولیه یک شیء  action sheet عادی می باشد. بهترین بخش را برای آخر کار نگه داشته ایم. جادوی بلوک ها و completion handler ها را با ساختن متد تکمیلی تحسین می کنیم:

- (IBAction)showActionSheet:(id)sender {
    CustomActionSheet *customActionSheet = [[CustomActionSheet alloc] initWithTitle:@"AppCoda"
                                                                       delegate:nil
                                                              cancelButtonTitle:@"Cancel"
                                                         destructiveButtonTitle:nil
                                                              otherButtonTitles:@"Option 1", @"Option 2", @"Option 3", nil];
    
    [_customActionSheet showInView:self.view withCompletionHandler:^(NSString *buttonTitle, NSInteger buttonIndex) {
        NSLog(@"You tapped the button in index: %d", buttonIndex);
        NSLog(@"Your selection is: %@", buttonTitle);
    }];
}

به محض فراخوانی متد showInView:withCompletionHandler: ، ما بلوک را تعریف می کنیم و بدون این که حتی یک خط کد در جایی نوشته شود ، می توانیم به صورت محلی callback ساخته شده توسط کلاس سفارشی خود را مدیریت نماییم! از آن جایی که این یک مثال است ، نیازی به مدیریت عنوان و ایندکس کلید به شیوه خاصی نداریم ، بنابراین ، فقط مقادیر مربوط به کلید انتخاب شده را log می کنیم. البته ، اگر برای استفاده از کلاس CustomActionSheet در پروژه خود نقشه ای داشته باشید ، احتمالاً نیاز به افزودن متدهای نماینده action sheet بیشتری خواهید داشت ، اما اکنون یک تصویر بزرگ در ذهن خود دارید و مطمئن هستیم که هر مورد سفارشی را که تمایل دارید اضافه نمایید ، می توانید مدیریت کنید.

اجازه دهید یک چیز دیگر را متذکر شویم. ما از شیء customActionSheet  به عنوان متغیر عضو کلاس استفاده می کنیم ، در عوض به سادگی آن را به صورت محلی اعلان می کنیم ، زیرا ما نیاز داریم که یک strong reference به شیء action sheet سفارشی داشته باشیم تا کد بلوک اجرا شود ، حتی بعد از این که اجرای متد IBActin پایان یافته باشد.

کلاس سفارشی که ما ساختیم ، مورد واقعی است که در عمل می توان بلوک را در آن قرار داد. امیدواریم که تمام مطالب ارائه شده در این بخش مفید باشد و ابزار سودمندی را برای شما فراهم نماید. اگر چنین حسی دارید ، سعی کنید استفاده مشابهی از UIAlertView به جای یک action sheet نمایید و آن را به عنوان تکلیف انجام دهید!

بلوک ها و چندنخی (multithreading)

علاوه بر تمام مطالب فوق ، بلوک ها در هنگامی پیاده سازی اپلیکیشن های multithreading نیز می توانند سودمند باشند. موضوع مهم این است که کد نوشته شده برای اجرا در thread های ثانویه  در یک مکان قرار دارند ، از این رو اعمال کنترل بر روی اپلیکیشن نیز راحت تر صورت می گیرد.

متداول ترین متد مورد استفاده برای اجرای تسک های چند نخی در ترکیب با بلوک ها ، متد Grand Central Dispatch است که به اختصار به صورت GCD شناخته می شود. آن چه که ما باید انجام دهیم تا بتوانیم یک بلوک را با استفاده از GCD تعریف کنیم ، ایجاد یک صف جدید و پیاده سازی بدنه بلوک می باشد. مثال زیر نشان می دهد که چگونه می توانیم به آسانی این کار را انجام دهیم. به خاطر سادگی مثال ، کد نوشته شده در داخل بلوک هیچ point ی ندارد. اگر پیاده سازی اپلیکیشن demo را قدم به قدم تا اینجا دنبال کرده باشید ، پس می توانید کار را با افزودن قطعه کد بعدی در متد viewDidLoad دنبال نمایید.

    NSLog(@"Preparing to run code in secondary thread...");
    dispatch_queue_t myQueue = dispatch_queue_create("My Queue", NULL);
    dispatch_async(myQueue, ^{
        NSLog(@"Running code in secondary thread...");
        
        int value = 0;
        for (int i=0; i<100; i++) {
            for (int j=0; j<100; j++) {
                for (int n=0; n<100; n++) {
                    value += j;
                }
            }
        }
        
        NSLog(@"From secondary thread: value = %d", value);
    });
    
    NSLog(@"This is main thread again...");

همان طور که مشاهده می شود ، ما ابتدا یک صف جدید ایجاد می کنیم و سپس ، در داخل تابع dispatch_async  بلوک خود را تعریف می کنیم. در اینجا می توانیم هر کد موردنیاز برای اپلیکیشن خود را اضافه نماییم. چیزی که انتظار داریم در debugger ببینیم ، مطابق تصویر زیر است:

کامپایل نمودن و اجرای اپ

همان طور که در بخش بازبینی اپ گفتیم ، این اپ demo از بخش های مختلف بسیاری تشکیل یافته است و بسیاری از این بخش ها ، فقط پیامی را در debugger نشان می دهند. تعامل خاصی وجود ندارد و از نظر بصری اپ واقعاً خیلی ضعیف به نظر می رسد. با این حال ، آن چه که شما می توانید در پس تمام این بخش ها پیدا نمایید ، چیزهای واقعاً مفیدی هستد. توجه داشته باشید که پس از تست برنامه ، مهم ترین چیز این است که شما بروید و چندین بلوک را برای خود بسازید. زمانی که شما به درستی بلوک ها را پیاده سازی نمایید ، بدان معناست که شما واقعاً در یک مسیر درستی قرار دارید.

خلاصه

غالباً این واقعیت پذیرفته شده است که بلوک ها در آینده در مسیر نوشتن برنامه های ما قرار دارند و تا به امروز بلوک ها به این نقطه رسیده اند. بسیاری از فریم ورک ها تغییر یافته و بسیاری از متدها دوباره بازنویسی شده اند ، و اکنون از بلوک ها استفاده می کنند. اگر با بلوک ها ناآشنا هستید ، بهتر است که کار یادگیری آنها را شروع نمایید ، زیر زمانی فرا خواهد رسید که مجبور به استفاده از آنها خواهید شد. بلوک ها می توانند بسیار قدرتمند و کمک کننده باشند. همان طور که قبلاً ثابت شده است ، بلوک ها به ما کمک می کنند تا کدها را در سطح بالایی از نظم و ترتیب نگه داریم و از طرفی ، کنترل کدها از طریق بلوک ها آسان تر انجام می شود. با این حال ، بلوک ها نمی توانند جایگزین هر چیزی شوند. برای برخی از تسک های خاص ، نیاز به پیاده سازی متدهای نماینده یا برخی از تکنیک های برنامه نویسی ، سر جای خود باقی می مانند. با این وجود ، این موضوع واضح است که هم اکنون می توان از بلوک ها بیش از آن چه که در کدهای ما آورده شده است ، استفاده نمود و در سطح بالاتری از Objective-C از آنها بهره مند شد. از این رو ، امیدواریم که راه خود را در دنیای بلوک ها پیدا نمایید و موفق به انجام برنامه نویسی عالی با استفاده از آنها شوید.

فصلِ: 3 , تعداد قسمت ها: 179 , سطح: صفر تا صد

این فصل در یک نگاه:

در این دوره آموزشی ، برنامه نویسی اندروید و ios را با استفاده از زامارین خواهیم آموخت. همچنین به صورت کاملا پروژه محور ، اپلیکیشن فروشگاهی مشابه دیجی کالا را پیاده سازی خواهیم کرد. در انته…
فصلِ: 5 , تعداد قسمت ها: 221 , سطح: صفر تا صد
موضوعات: آموزش IOS

این فصل در یک نگاه:

در این فصل:-نمایش notification به کاربر زمانی که اتفاقاتی از قبیل لایک کردن پست و ... میافتد(این مبحث مبحثی مهم بوده و ج…

  توضیحات کلی دوره: با سلام خوش اومدین به حرفه ای ترین دوره ی Swift ابتدای کار ممکن است سوالی برای شما پیش آید: -من نیازی به ساخت اپلیکیشن اجتماعی ندارم چرا باید این دوره را ببینم؟ ج…
فصلِ: 7 , تعداد قسمت ها: 159 , سطح: صفر تا صد
موضوعات: آموزش IOS

این فصل در یک نگاه:

اپل نویس حرفه ای شوید... با این پکیج کسب درآمد میلیونی کنید....   در این پکیج به نکات ریز و درشت زیادی پرداختیم که خیلی خیلی میتونه به شما کمک کنه که تبدیل به برنامه نویس حرفه ای شوید... …
فصلِ: 12 , تعداد قسمت ها: 126 , سطح: صفر تا صد
موضوعات: آموزش IOS

این فصل در یک نگاه:

فصل 16 فصل آخرمون هست و میایم توی این فصل یه سری مباحث کوچیکی که جامونده و کارهای نهایی برای انتشار برنامه توی مایکت های…

با سلام نکته:هیچ نیازی به mac و یا iphone نیست... نکته:هیچ نیازی به بلد بودن برنامه نویسی از قبل نیست... مباحثی که توی این دوره مرور میکنیم میتونه ما رو از سطح صفر برنامه نویسی ios به صد …
فصلِ: 6 , تعداد قسمت ها: 194 , سطح: صفر تا صد

این فصل در یک نگاه:

در این فصل آپدیت های مربوط به دوره را قرار میدهیم…

با سلام و خسته نباشد خدمت کلیک سایتی های عزیز در ادامه با توضیحات مختصری درمورد دوره ی react native با ما همراه باشید: React Native چیست؟ قطعا یکی از آرزوهای برنامه نویسان این میباشد که ب…
فصلِ: 5 , تعداد قسمت ها: 51 , سطح: صفر تا صد

این فصل در یک نگاه:

اموزش پرداخت درون برنامه ای بازار در یونیتی-اموزش خرید سکه در بازی-اموزش خرید مصرفی و غیر مصرفی…

توضیحات کلی مجموعه: آموزش مقدماتی تا پیشرفته یونیتی(ساخت بازی توپ چرخنده-اموزش بازی دوبعدی-اموزش بازی سه بعدی اول شخص شوتر-اموزش بازی سه بعدی رالی (ماشین سواری))   سرفصلهای دوره: نصب ی…
فصلِ: 2 , تعداد قسمت ها: 68 , سطح: صفر تا صد

این فصل در یک نگاه:

آموزش ساخت یک فروشگاه کوچک-آموزش کار با bottom navigation -آموزش کار با تب بار-آموزش کار با scrollview - آموزش کار با ان…

توضیحات کلی مجموعه: آموزش دوره فلاتر از پایه تا پیشرفته(این دوره به دوره متخصص فلاتر تغییر پیدا کرد) درسال های گذشته تعدا زیادی فریمورک معرفی شد که هرکدام تجربه خاص خودش رو داشت،اما فلاتر …
فصلِ: 5 , تعداد قسمت ها: 25 , سطح: صفر تا صد

این فصل در یک نگاه:

فصل پنجم…

توضیحات کلی مجموعه: درباره گیت: لذت پیش بردن پروژه های برنامه نویسی خود را با بهترین ورژن کنترل سیستم جهان تجربه کنید کامل ترین دوره ی آموزشی گیت و گیت هاب به همراه مثال های کاربردی گی…

تولید شده توسط کلیک سایت

پشتیبانی آنلاین
آماده پاسخگویی هستیم
انتخاب تصویر جهت ارسال:
در حال ضبط صدا

(جهت توقف و یا لغو ضبط از دکمه های زیر استفاده کنید)

توقف و ارسال :
لغو ضبط
در حال حاضر تمامی کارشناسان آفلاین هستند. همواره می توانید با شماره تلگرام / واتساپ 09010005000 به صورت آنلاین با ما در ارتباط باشید. جهت ورود به واتساپ کلیک کنید
0 پیام جدید
پشتیبان در حال تایپ ...
ارسال تصویر ضبط صدا
0 کارشناسان آنلاین می باشند
این گفت و گو توسط پشتیبان به اتمام رسید