Objective-C: ماهیت زبان و جایگاه آن در توسعه iOS

نویسنده: IT Sectr منتشر شده: 2026-02-09 زمان مطالعه: 8 دقیقه

Objective-C — زبان برنامه‌نویسی با ارسال پویای پیام که توسط برد کاکس در دهه ۱۹۸۰ ساخته شد. اپل Objective-C را به عنوان زبان اصلی برای NeXTSTEP و سپس برای iOS SDK انتخاب کرد. Programming With Objective-C — معرفی نحو پیام و مدیریت حافظه.

نکات اصلی

  • Objective-C — ابرمجموعه‌ای دقیق از C با نحو پیام در براکت‌های مربع و runtime پویا
  • Message passing — فراخوانی متد از طریق [object selector:argument] با جستجوی پویای پیاده‌سازی از طریق objc_msgSend
  • Categories — سازوکار افزودن متد به کلاس‌های موجود بدون وراثت و بدون دسترسی به کد منبع
  • Blocks — توابع ناشناس با بستار، پیش‌نیاز Swift closures
  • ARC vs MRC — شمارش مرجع خودکار و دستی برای مدیریت حافظه

Objective-C چیست؟

Objective-C — زبان برنامه‌نویسی که C را با قابلیت‌های برنامه‌نویسی شیء‌گرا به سبک Smalltalk توسعه می‌دهد. کد Objective-C از طریق LLVM یا GCC به کد ماشین بومی کامپایل می‌شود و سازگاری کامل معکوس با C را حفظ می‌کند — هر کد C در Objective-C معتبر است.

اپل NeXT (همراه با Objective-C) را در سال ۱۹۹۷ خریداری کرد. این زبان به پایه Cocoa و Cocoa Touch — چارچوب‌های macOS و iOS تبدیل شد. از سال ۲۰۱۴ اپل Swift را به عنوان جایگزین معرفی می‌کند، اما Objective-C برای پروژه‌های legacy و برخی چارچوب‌های سیستمی حیاتی باقی مانده است. طبق داده‌های اپل (WWDC 2024)، حدود ۳۵٪ از برنامه‌های App Store همچنان حاوی کد Objective-C هستند.

ویژگی کلیدی — runtime پویا. برخلاف Swift که در آن فراخوانی متدها در مرحله کامپایل حل می‌شوند، Objective-C پیام‌ها را در زمان اجرا از طریق تابع objc_msgSend ارسال می‌کند. این امکان بازتعریف متدها در لحظه (method swizzling)، افزودن پویای کلاس‌ها و استفاده از forward invocation برای selectorهای ناموجود را فراهم می‌کند.

نحو: C + لایه شیء

هر کد C در Objective-C معتبر است. لایه شیء کلاس‌ها (@interface/@implementation)، دسته‌بندی‌ها، پروتکل‌ها (@protocol) و تایپ‌بندی پویا (id) را اضافه می‌کند. فایل‌ها دارای پسوندهای .m (پیاده‌سازی) و .h (سرآیندها) هستند.

نحو پیام و ارسال پویا

نحو پیام — تفاوت اصلی Objective-C با زبان‌های C-مانند. به جای object.method(argument) از [object method:argument] استفاده می‌شود. هر پیام از objc_msgSend عبور می‌کند که به طور پویا پیاده‌سازی متد را در runtime جستجو می‌کند.

objective-c
// نحو پیام با پارامترهای نام‌گذاری شده
NSString *greeting = [NSString stringWithFormat:@"Hello, %@", name];

// پیام‌های تو در تو
NSArray *sortedArray = [[array sortedArrayUsingSelector:@selector(compare:)] copy];

// بررسی نوع از طریق introspection
if ([object isKindOfClass:[UIView class]]) {
    UIView *view = (UIView *)object;
    view.backgroundColor = [UIColor redColor];
}

Dynamic dispatch امکان بازتعریف متدها در runtime (method swizzling) را فراهم می‌کند — تکنیکی قدرتمند اما خطرناک. به عنوان مثال، چارچوب‌هایی مانند AFNetworking و Aspects از swizzling برای رهگیری فراخوانی‌های URLSession استفاده می‌کنند. اپل هشدار می‌دهد: swizzling در صورت استفاده نادرست می‌تواند عملکرد چارچوب‌های سیستمی را مختل کند.

دسته‌بندی‌ها و توسعه‌دهنده‌های کلاس

Categories — امکان منحصربه‌فرد Objective-C برای افزودن متد به کلاس‌های موجود (از جمله سیستمی، مانند NSString و UIView) بدون وراثت و بدون دسترسی به کد منبع. دسته‌بندی‌ها از طریق @interface ClassName (CategoryName) اعلام می‌شوند.

objective-c
// فایل UIColor+Hex.h — دسته‌بندی برای UIColor
@interface UIColor (Hex)
+ (instancetype)colorWithHex:NSUIntegerhex;
@end

// فایل UIColor+Hex.m — پیاده‌سازی
@implementation UIColor (Hex)
+ (instancetype)colorWithHex:NSUIntegerhex {
    CGFloat r = ((hex >> 16) & 0xFF) / 255.0;
    CGFloat g = ((hex >> 8) & 0xFF) / 255.0;
    CGFloat b = (hex & 0xFF) / 255.0;
    return [self colorWithRed:r green:g blue:b alpha:1.0];
}
@end

Extensions (Class Extension) — نوع خاصی از دسته‌بندی که در فایل .m بدون نام اعلام می‌شود: @interface ClassName (). برخلاف دسته‌بندی‌ها، extensions می‌توانند نه تنها متدها، بلکه ivar (متغیرهای نمونه) و property را نیز اضافه کنند. Extensions برای پنهان کردن API داخلی از ماژول‌های خارجی استفاده می‌شوند.

بلوک‌ها — توابع ناشناس با بستار

Blocks — توابع ناشناس در Objective-C که متغیرها را از محدوده دید خارجی می‌گیرند. نحو بلوک‌ها: ^(int x) { return x * 2; }. Blocks در UIKit برای handlerهای callback، در Grand Central Dispatch برای وظایف ناهمگام و در مجموعه‌های NSArray/NSDictionary برای عملیات تابعی استفاده می‌شوند.

objective-c
// اعلام نوع بلوک
typedef void (^CompletionBlock)(BOOL success, NSError *error);

// بلوک به عنوان پارامتر
- (void)fetchDataWithCompletion:(CompletionBlock)completion {
    __weak typeof(self) weakSelf = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        BOOL result = [weakSelf processData];
        if (completion) {
            completion(result, nil);
        }
    });
}

مدیریت حافظه در بلوک‌ها حیاتی است. بلوک‌ها self را با مرجع قوی می‌گیرند که در استفاده مستقیم retain cycle ایجاد می‌کند. راه‌حل — __weak typeof(self) weakSelf = self، با بررسی بعدی در داخل بلوک. این مشکل در Swift از طریق لیست‌های capture [weak self] کاملاً حل شده است.

ARC و MRC: مدیریت حافظه

Objective-C مسیری از MRC (Manual Reference Counting) تا ARC (Automatic Reference Counting) را طی کرده است. در MRC برنامه‌نویس به صورت دستی retain (افزایش شمارنده)، release (کاهش) و autorelease (release با تأخیر) را فراخوانی می‌کرد. خطا در این فراخوانی‌ها منجر به نشت حافظه یا crash به دلیل dangling pointers می‌شد.

عملیاتMRCARC
ایجاد شیء[[Object alloc] init][[Object alloc] init]
نگهداری مرجع[object retain]خودکار
آزادسازی[object release]خودکار
آزادسازی خودکار[object autorelease]خودکار (نیاز نیست)
مرجع Weak__weak وجود نداشت__weak (nil خودکار)

ARC در Xcode 4.2 و LLVM 3.0 (2011) معرفی شد. کامپایلر به طور خودکار retain/release را در مرحله کامپایل با تحلیل طول عمر اشیاء درج می‌کند. ARC جمع‌آوری زباله (garbage collection) نیست — این تحلیل استاتیک با درج‌های خودکار است. Objective-C ARC با Swift ARC سازگار است: هر دو از یک سیستم شمارش مرجع در سطح runtime استفاده می‌کنند.

تعامل با Swift از طریق Bridging Header

استفاده مشترک از Objective-C و Swift در یک پروژه — رویه معمول برای پروژه‌های legacy. اپل Bridging Header را ارائه می‌دهد — فایلی که به طور خودکار تولید می‌شود و از طریق آن Swift کلاس‌های Objective-C را می‌بیند و Objective-C کلاس‌های Swift را که از NSObject ارث برده‌اند می‌بیند.

objective-c
// ProjectName-Bridging-Header.h
// Swift این سرآیندها را به طور خودکار می‌بیند
#import "LegacyManager.h"
#import "NetworkClient.h"
#import "DataStore.h"

مهاجرت از Objective-C به Swift — فرآیندی مرحله‌ای. فایل‌های جدید به Swift نوشته می‌شوند، فایل‌های قدیمی به تدریج بازنویسی می‌شوند. Bridging Header به طور خودکار هنگام افزودن اولین فایل Swift به پروژه Objective-C تولید می‌شود. برای دید معکوس (ObjC → Swift) Xcode فایل -Swift.h را تولید می‌کند که حاوی @interface برای کلاس‌های Swift علامت‌گذاری شده با @objc است.

swift
// کلاس Swift قابل مشاهده از Objective-C
@objc class SwiftRouter: NSObject {
    @objc func navigateToProfile(userId: Int) {
        // پیاده‌سازی
    }
}

محدودیت‌ها: انواع value Swift (struct, enum) مستقیماً از Objective-C قابل مشاهده نیستند — باید آنها را در class با @objc بپیچید. Generics در Swift به صورت محدود از Objective-C در دسترس است. رویکرد توصیه‌شده — نوشتن کد جدید به Swift و بازنویسی کد Objective-C موجود فقط هنگام تغییر قابلیت مربوطه.

Runtime و method swizzling در Objective-C

مزیت اصلی Objective-C نسبت به Swift — دسترسی کامل به runtime. Method swizzling، جایگزینی پیاده‌سازی متدها در زمان اجرا، امکان بازتعریف متدهای سیستمی بدون وراثت را فراهم می‌کند. کتابخانه‌هایی مانند Aspects و JRSwizzle از این امکان برای AOP (برنامه‌نویسی جنبه‌گرا) — پایش، تحلیل و لاگ‌گیری استفاده می‌کنند.

Forward invocation — یکی دیگر از قابلیت‌های runtime: اگر شیء به selector پاسخ ندهد، سیستم forwardInvocation: را فراخوانی می‌کند و امکان هدایت پیام به شیء دیگر را فراهم می‌کند. این اساس الگوی Proxy در Objective-C (NSProxy) است که برای مقداردهی تأخیری و اشیاء توزیع‌شده استفاده می‌شود.

اپل توصیه می‌کند استفاده از ترفندهای runtime را در کد جدید به حداقل برسانید و به تایپ‌بندی استاتیک Swift اولویت دهید. با این حال، در پروژه‌های legacy آشنایی با objc_msgSend، method_exchangeImplementations و objc_getAssociatedObject برای پشتیبانی از پایگاه کد موجود ضروری است.

Property و Key-Value Observing

Objective-C از property به عنوان شکر نحوی روی ivar با getter/setter پشتیبانی می‌کند. اصلاح‌کننده‌های atomic/nonatomic، strong/weak/copy، readonly/readwrite و assign/retain رفتار حافظه و ایمنی نخ را تعیین می‌کنند. Key-Value Observing (KVO) — سازوکار مشاهده تغییرات خصوصیات تعبیه‌شده در runtime: هر شیء می‌تواند از طریق addObserver تغییرات خصوصیات شیء دیگر را دنبال کند.

سوالات متداول

نحو پیام در Objective-C چیست؟

فراخوانی متد به صورت [object selector:argument] است. پیام از objc_msgSend عبور می‌کند که به طور پویا پیاده‌سازی را در runtime پیدا می‌کند. selector نام متد است (@selector(methodName))، نه اشاره‌گر به تابع. این امکان swizzling و forward invocation را فراهم می‌کند.

دسته‌بندی‌ها (Categories) چه تفاوتی با توسعه‌دهنده‌ها (Extensions) دارند؟

Category (@interface ClassName (Name)) متدها را به هر کلاسی (از جمله سیستمی) بدون وراثت اضافه می‌کند. Extension (@interface ClassName ()) در فایل .m اعلام می‌شود و می‌تواند property و ivar اضافه کند. Category نمی‌تواند ivar اضافه کند، extension می‌تواند.

بلوک‌ها (Blocks) در Objective-C چیست؟

Blocks — توابع ناشناس با نحو ^(پارامترها) { بدنه } که متغیرها را از زمینه می‌گیرند. مشابه لامبداها در C++ و closures در Swift. برای جلوگیری از retain cycles هنگام گرفتن self نیاز به __weak دارند. در UIKit، GCD و Foundation استفاده می‌شوند.

تفاوت بین ARC و MRC چیست؟

MRC — شمارش مرجع دستی: برنامه‌نویس retain، release، autorelease را فراخوانی می‌کند. ARC — خودکار: کامپایلر retain/release را بر اساس تحلیل استاتیک درج می‌کند. ARC GC نیست — اشیاء بلافاصله پس از صفر شدن شمارنده آزاد می‌شوند. ARC از اصلاح‌کننده‌های __weak و __strong پشتیبانی می‌کند.

آیا می‌توان Objective-C و Swift را در یک پروژه استفاده کرد؟

بله، از طریق Bridging Header. Swift Objective-C را از طریق این سرآیند می‌بیند، Objective-C Swift را از طریق -Swift.h می‌بیند. کلاس‌های Swift باید از NSObject ارث برده و با @objc علامت‌گذاری شوند. struct و enum از Swift مستقیماً برای Objective-C قابل مشاهده نیستند.

خلاصه

  • Objective-C — ابرمجموعه‌ای دقیق از C با runtime پویا و نحو پیام برای Cocoa/Cocoa Touch
  • Message passing — فراخوانی از طریق [object method] با ارسال پویا از طریق objc_msgSend و امکان swizzling
  • Categories — افزودن متد به کلاس‌های موجود بدون وراثت، از جمله کلاس‌های سیستمی اپل
  • Blocks — توابع ناشناس با بستار که برای جلوگیری از retain cycles نیاز به __weak دارند
  • ARC vs MRC — تکامل از retain/release دستی به شمارش مرجع خودکار از طریق کامپایلر
  • Bridging Header — سازوکار کار مشترک Swift و Objective-C در یک پروژه برای مهاجرت تدریجی
  • اهمیت legacy — حدود ۳۵٪ از برنامه‌های App Store حاوی کد Objective-C نیازمند پشتیبانی هستند

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید