Responder Chain یک مکانیسم iOS است که رویدادهای لمس، فشار کلیدها و جستها را بهصورت متوالی از طریق سلسلهمراتب اشیاء UIResponder انتقال میدهد، تا اینکه یکی از آنها رویداد را پردازش کند. زنجیره از شیئی که رویداد را کشف کرده آغاز میشود و در سلسلهمراتب به بالا حرکت میکند: از view به superview آن، سپس به view controller، window و در نهایت به UIApplication. به گزارش Apple Developer Documentation (2026)، این الگو به شما امکان تقسیم مسئولیت پردازش رویدادها را بین کامپوننتهای رابط میدهد و انعطافپذیری بدون اتصال سفت به یک handler خاص فراهم میکند.
نکات کلیدی
Responder Chain یک تسلسل از اشیاء UIResponder است که iOS از طریق آنها رویدادهای ورودی مانند لمس، فشار کلیدها و شتابسنج را منتقل میکند. هر شیء در این زنجیره این قابلیت را دارد که رویداد را پردازش کند یا آن را به شیء responder بعدی از طریق ویژگی next انتقال دهد.
این مکانیسم بر اساس سلسلهمراتب view استوار است: وقتی لمسی اتفاق میافتد، iOS ابتدا تعیین میکند که کدام view فشار داده شده ( از طریق hit-testing) و زنجیرهای از آن view تا UIApplication ایجاد میکند. UIApplication آخرین حلقه زنجیره است — اگر رویداد به آن برسد و پردازش نشود، صرفاً نادیده گرفته میشود.
به گزارش Apple، این الگو برای کپسولهسازی منطق پردازش رویدادها بسیار مهم است. توسعهدهنده میتواند رفتار یک view خاص را بدون تأثیر بر سایر عناصر سلسلهمراتب بازنویسی کند. به عنوان مثال، UITextField با دریافت فوکوس به first responder تبدیل میشود و رویدادهای صفحه کلید را بدون نیاز به تغییرات در UIViewController والد دریافت میکند.
پردازش رویدادها از طریق Responder Chain در دو مرحله انجام میشود: ابتدا iOS تعیین میکند که کدام view رویداد را دریافت کرده (hit-testing)، سپس زنجیره responderها را برای پردازش آن آغاز میکند. اگر شیئی روش مناسب را پیادهسازی نکند، رویداد به بیشتر انتقال داده میشود.
زنجیره بر اساس first responder فعلی و سلسلهمراتب view به صورت پویا شکل میگیرد. ترتیب ستاندارد به این صورت است: first responder → view آن → superview → UIViewController → root view → UIWindow → UIApplication. اگر هریک از این اشیاء بهعنوان مثال touchesBegan را پیادهسازی کند، رویداد در آن سطح پردازش شده و بیشتر انتقال داده نمیشود.
import UIKit
class CustomView: UIView {
override func touchesBegan(
_ touches: Set<UITouch>,
with event: UIEvent?
) {
// لمس در این سطح از view پردازش شد
print("CustomView لمس را پردازش کرد")
// رویداد را در طول زنجیره ارسال کن
super.touchesBegan(touches, with: event)
}
}
ویژگی کلیدی این است که فراخوانی super.touchesBegan اجباری نیست. اگر فراخوانی نشود، رویداد تنها در سطح جاری پردازش شده و از Responder Chain بیشتر نخواهد گذشت. این به توسعهدهنده کنترل کاملی بر اینکه کدام اشیاء در پردازش شرکت میکنند میدهد.
وقتی شیئی رویدادی را دریافت میکند اما آن را پردازش نمیکند (روش را بازنویسی نمیکند)، iOS به طور خودکار رویداد را به شیء responder بعدی از طریق ویژگی next انتقال میدهد. این ویژگی یک لیست یکطرفه ایجاد میکند که Responder Chain نامیده میشود.
UIViewController بین view خود و UIWindow قرار دارد: اگر view رویداد را پردازش نکند، کنترلر شانس انجام این کار را دارد. این بهویژه برای منطق مشترک مفید است — به عنوان مثال، پردازش جستی که باید در تمام صفحه کار کند، صرفنظر از اینکه چه viewی زیر انگشت کاربر است.
Hit-Testing فرآیندی است که iOS به کمک آن تعیین میکند که کدام view در زیر نقطه لمس قرار دارد. روش hitTest:withEvent: سلسلهمراتب view را از UIWindow به پایین پیمایش میکند و بررسی میکند که کدامیک از viewهای تابع نقطه لمس را شامل میشود و مخفی نیست.
الگوریتم به صورت بازگشتی کار میکند: برای هر سطح، iOS viewها را به ترتیب معکوس اضافه بررسی میکند (ابتدا بالاییها). اگر view مخفی نباشد، شفاف نباشد و نقطه در bounds آن باشد، hitTest به صورت بازگشتی برای تمام subviewها فراخوانده میشود. عمیقترین view که همه شرایط را برآورده کند، hit-test view میشود — اولین شیء در Responder Chain.
override func hitTest(
_ point: CGPoint,
with event: UIEvent?
) -> UIView? {
if isUserInteractionEnabled &&
isHidden == false &&
alpha > 0.01 &&
point(inside: point, with: event) {
return super.hitTest(point, with: event)
}
return nil
}
توسعهدهندگان میتوانند hitTest را بازنویسی کنند تا رفتار ستاندارد را تغییر دهند. به عنوان مثال، منطقه لمس را برای یک دکمه کوچک گشتردن یا رویداد را به view دیگری که اصلاً زیر انگشت نیست هدایت کنید. این ابزاری قدرتمند برای ایجاد عناصر تعاملی سفارشی است.
UIResponder کلاس پایه برای تمام اشیائی است که میتوانند رویدادها را در iOS پردازش کنند. UIView، UIViewController، UIApplication و UIWindow از UIResponder ارث بردهاند. این کلاس یک مجموعه روش را فراهم میکند که میتوان آنها را برای پردازش انواع مختلف رویدادها بازنویسی کرد.
گروههای اصلی روشها شامل touchesBegan، touchesMoved، touchesEnded، touchesCancelled برای لمسها؛ pressesBegan، pressesEnded برای دکمههای فیزیکی؛ و motionBegan، motionEnded برای رویدادهای شتابسنج میشود. هر روش یک مجموعه از اشیاء UITouch یا UIPress و یک ارجاع به UIEvent دارای فاقداتای اضافی درباره رویداد دریافت میکند.
| روش UIResponder | کاربرد |
|---|---|
| touchesBegan | در شروع لمس فراخوانده میشود |
| touchesMoved | در حرکت انگشت فراخوانده میشود |
| touchesEnded | در رها کردن انگشت فراخوانده میشود |
| touchesCancelled | در قطع شدن فراخوانده میشود (تماس، کشیدن پرده) |
| pressesBegan | در فشار دکمه فیزیکی فراخوانده میشود |
مهم است بدانید که iOS این روشها را تنها برای first responder و اشیاء بعدی در زنجیره فراخوانده میکند. اگر هیچ شیئی روشی را بازنویسی نکرده باشد، رویداد خطا ایجاد نمیکند — صرفاً نادیده گرفته میشود. برای اشکالزدایی پردازش رویدادها از Symbolic Breakpoint بر UIResponder touchEvent استفاده کنید.
کامپوننتهای ستاندارد UIKit به طور فعالی از Responder Chain برای کار خود استفاده میکنند. UITextField با دریافت فوکوس به first responder تبدیل میشود که به طور خودکار صفحه کلید را باز میکند. UIButton لمسها را از طریق مکانیسم UIControl پردازش میکند که آن نیز بر responder chain استوار است.
UITableView و UICollectionView از زنجیره responderها برای پردازش انتخاب سلولها و جستهای پیمایش استفاده میکنند. اگر کاربر سلولی را لمس کند، رویداد را ابتدا خود سلول، سپس UITableView و فقط بعد از آن UIViewController دریافت میکند. UIGestureRecognizer اولویت بالاتری از touchesBegan دارد — اگر به view یک شناساینده جست اضافه شود، آن ابتدا رویداد را دریافت خواهد کرد.
به گزارش Apple، استفاده صحیح از Responder Chain برای دسترسپذیری برنامه بسیار مهم است. VoiceOver و سایر فناوریهای کمکی از زنجیره responderها برای پیمایش بین عناصر رابط استفاده میکنند. اگر زنجیره شکسته شود، کاربران محدود نمیتوانند با برنامه تعامل کنند.
UIMenuController برای نمایش منوی کتکستی نیز از Responder Chain استفاده میکند. وقتی کاربر منو را فراخوان میکند، سیستم به دنبال first responderی میگردد که روشهای canPerformAction و روشهای عمل مناسب را پیادهسازی کند. منو تنها برای اعمالی نمایش داده میشود که responder فعلی آنها را پشتیبانی میکند.
این به عنوان مثال امکان نمایش دستورات برش، رونویسی، چسبانن را تنها وقتی که UITextField در فوکوس است و پنهان کردن آنها هنگام کار با UILabel فراهم میکند. توسعهدهنده میتواند با پیادهسازی آنها در زیرکلاس UIResponder و بازگرداندن true از canPerformAction، اعمال سفارشی را به منوی کتکستی اضافه کند.
ایجاد یک شیء responder سفارشی به توسعهدهنده کنترل کاملی بر پردازش رویدادها میدهد. برای این کار باید یک زیرکلاس UIResponder (یا UIView/UIViewController) ایجاد کرده و روشهای مورد نیاز پردازش رویداد را بازنویسی کنید.
اشیاء responder سفارشی معمولاً برای پردازش جستهای ویژه استفاده میشوند که توسط UIGestureRecognizer ستاندارد پوشش داده نمیشوند. به عنوان مثال، تشخیص کشیدن اشکال، ترکیبات پیچیده multi-touch یا الگوهای ورودی انحصاری. یک responder سفارشی میتواند رویدادها را از چندین انگشت جمعآوری کرده و بر اساس ترکیب آنها تصمیم گیری کند.
class DrawingResponder: UIResponder {
private var activeTouches: [UITouch: CGPoint] = [:]
override func touchesBegan(
_ touches: Set<UITouch>,
with event: UIEvent?
) {
for touch in touches {
activeTouches[touch] = touch.location(in: self)
}
}
override func touchesMoved(
_ touches: Set<UITouch>,
with event: UIEvent?
) {
for touch in touches {
let currentPoint = touch.location(in: self)
activeTouches[touch] = currentPoint
drawLine(from: activeTouches[touch]!, to: currentPoint)
}
}
}
هنگام ایجاد یک responder سفارشی، پیکربندی مناسب زنجیره next مهم است. اگر شیء شما بخشی از سلسلهمراتب ستاندارد UIKit نیست، باید صریحاً مشخص کنید که کدام شیء next responder آن خواهد بود. این تضمین میکند که رویدادهای پردازشنشده به حرکت خود در Responder Chain ادامه دهند.
سؤالات متداول
Responder Chain یک زنجیره سلسلهمراتبی از اشیاء UIResponder است که iOS از طریق آن رویدادهای لمس، فشار و جست را به طور متوالی انتقال میدهد. اگر شیئی رویداد را پردازش نکند، آن به شیء responder بعدی در زنجیره تا UIApplication انتقال داده میشود.
ترتیب را میتوان با بازنویسی ویژگی next در شیء UIResponder خود تغییر داد. با بازگرداندن شیء دیگری به جای شیء ستاندارد، رویدادهای پردازشنشده را به آن هدایت میکنید. این برای سلسلهمراتبهای غیراستاندارد مفید است، به عنوان مثال وقتی یک کانتینر سفارشی چندین کنترلر تابع را مدیریت میکند.
Hit-Testing تعیین میکند که کدام view در زیر نقطه لمس قرار دارد (دریافت کننده اصلی)، و Responder Chain تعیین میکند چگونه رویداد بین اشیاء بعد از hit-test انتقال داده میشود. Hit-test اولین شیء را پیدا میکند، responder chain اگر آن شیء رویداد را پردازش نکند مسیریابی بیشتر را فراهم میکند.
برای قطع زنجیره، کافی است رویداد را در UIResponder خود پردازش کرده و super را فراخوان نکنید. به عنوان مثال، با بازنویسی touchesBegan و فراخوان نکردن super.touchesBegan، از انتقال رویداد به بیشتر جلوگیری میکنید. رویداد در سطح جاری پردازش شده و به حلقههای بعدی زنجیره نمیرسد.
شایعترین دلایل: isUserInteractionEnabled به false تنظیم شده، view مخفی است (isHidden = true)، alpha کمتر از 0.01 است، یا view خارج از bounds کانتینر والد است. همچنین بررسی کنید که آیا روی view یا superview آن UIGestureRecognizerی وجود دارد که رویدادها را پیش از touchesBegan گیرنداری میکند.
نتیجهگیری
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید