Background Task — مکانیزم iOS است که به برنامه اجازه میدهد عملیات شروعشده را پس از انتقال به حالت پسزمینه تکمیل کند. سیستم زمان محدودی (تا ۳۰ ثانیه) برای اجرای وظیفه اختصاص میدهد و پس از آن برنامه بهاجبار متوقف میشود. به گفته Apple, 2026، استفاده از expiration handler یک الزام اجباری برای تکمیل صحیح وظیفه پسزمینه است.
نکات اصلی
Background Task یک مکانیزم نرمافزاری iOS است که به برنامه اجازه میدهد زمان اجرا را پس از انتقال به حالت پسزمینه افزایش دهد. وقتی کاربر برنامه را میبندد، سیستم UIApplicationDelegate.applicationDidEnterBackground را فراخوانی میکند. اگر در این لحظه یک عملیات حیاتی (ذخیره داده، ارسال درخواست) در حال اجرا باشد، برنامه میتواند از طریق beginBackgroundTask زمان اضافی درخواست کند.
بدون استفاده از Background Task، برنامه پس از ۳–۵ ثانیه از رفتن به پسزمینه بهاجبار متوقف میشود. تمام عملیات ناتمام قطع میشوند: دادهها ذخیره نمیشوند، درخواستهای شبکه قطع میشوند، حالتها از دست میروند. Background Task تا ۳۰ ثانیه به برنامه برای تکمیل صحیح این عملیات فرصت میدهد.
beginBackgroundTask در iOS 4.0 — اولین نسخهای که از چندوظیفگی پشتیبانی میکرد — ظاهر شد. قبل از iOS 4، برنامه با فشردن دکمه Home کاملاً بسته میشد. از iOS 7 به بعد، Background Fetch و URLSession background configuration معرفی شدند. از iOS 13، Apple برای پروژههای جدید BGTaskScheduler را توصیه میکند، اما beginBackgroundTask برای عملیات کوتاهمدت همچنان کاربردی است.
beginBackgroundTask متدی از UIApplication است که وظیفه را ثبت میکند و یک شناسه یکتا UIBackgroundTaskIdentifier برمیگرداند. سیستم تایمر اجرای پسزمینه را افزایش میدهد. پس از اتمام زمان، expiration handler فراخوانی میشود و سپس برنامه باید برای تکمیل صحیح endBackgroundTask(identifier:) را فراخوانی کند.
گام ۱ — برنامه اعلان didEnterBackground را دریافت میکند. گام ۲ — beginBackgroundTask(expirationHandler:) فراخوانی میشود. گام ۳ — عملیات حیاتی (ذخیره، درخواست شبکه) اجرا میشود. گام ۴ — پس از اتمام، endBackgroundTask(identifier:) فراخوانی میشود. اگر عملیات در ۳۰ ثانیه تمام نشود — سیستم expiration handler را فراخوانی میکند و برنامه باید وظیفه را فوراً پایان دهد.
var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
func startBackgroundTask() {
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
// Expiration handler
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
}
func finishBackgroundTask() {
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
ویژگی backgroundTimeRemaining تعداد ثانیههای باقیمانده تا پایان اجباری وظیفه پسزمینه را برمیگرداند. مقدار در زمان واقعی کاهش مییابد. اگر برنامه در پسزمینه نباشد — DBL_MAX برمیگرداند. از این ویژگی برای تطبیق رفتار استفاده کنید: وقتی کمتر از ۵ ثانیه باقی مانده، عملیات طولانی را قطع کرده و پیشرفت را ذخیره کنید.
برنامه میتواند چندین Background Task را همزمان ثبت کند. هر وظیفه شناسه خود را دریافت میکند. زمان کل اجرا جمع میشود — اگر ۳ وظیفه ثبت شده باشد، برنامه میتواند تا ۹۰ ثانیه زمان بگیرد. با این حال، سیستم ممکن است در صورت اتمام منابع یا تجاوز از حد باتری، برنامه را زودتر پایان دهد.
Expiration handler بلوک کدی است که سیستم هنگام اتمام زمان اختصاصیافته برای وظیفه پسزمینه فراخوانی میکند. وجود expiration handler یک الزام اجباری Apple است. بدون آن، برنامه ممکن است توسط سیستم بهاجبار پایان یابد و دادهها از دست بروند.
Expiration handler باید حداقل اقدامات را برای ذخیره وضعیت برنامه انجام دهد: دادههای جاری را در حافظه پایدار ذخیره کند، endBackgroundTask را با شناسه مربوطه فراخوانی کند و شناسه را روی .invalid تنظیم کند. در داخل expiration handler شروع عملیات طولانی جدید ممنوع است — زمان اجرا به ۱–۲ ثانیه محدود میشود.
func handleExpiration() {
// پیشرفت اجرا را ذخیره میکنیم
saveProgressToUserDefaults()
// درخواستهای شبکه فعال را لغو میکنیم
currentTask?.cancel()
// Background Task را پایان میدهیم
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
// ثبت با expiration handler
backgroundTaskID = UIApplication.shared.beginBackgroundTask(
withName: "SaveDocument",
expirationHandler: handleExpiration
)
رایجترین خطا فراخوانی نکردن endBackgroundTask در داخل expiration handler است. در این صورت سیستم همچنان وظیفه را فعال در نظر میگیرد، برنامه به حالت Suspended نمیرود و باتری تخلیه میشود. خطای دوم شروع عملیات طولانی در داخل expiration handler است. سیستم ممکن است قبل از اتمام آنها برنامه را پایان دهد و دادهها از دست بروند.
در expiration handler زمان اجرا بحرانی کم است — معمولاً کمتر از ۱ ثانیه. بنابراین در داخل handler نمیتوان: محاسبات پیچیده، درخواستهای شبکه، نوشتن حجم زیاد داده در CoreData انجام داد. فقط عملیات اتمی: نوشتن یک کلید در UserDefaults، تنظیم پرچم وضعیت، فراخوانی endBackgroundTask.
بیایید پیادهسازی کامل Background Task برای ذخیره سند هنگام رفتن برنامه به پسزمینه را بررسی کنیم. مثال شامل ثبت وظیفه، اجرای عملیات با بررسی زمان باقیمانده و تکمیل صحیح از طریق endBackgroundTask است.
هنگام رفتن به پسزمینه، برنامه ذخیره یک سند بزرگ را آغاز میکند. Background Task تا ۳۰ ثانیه برای عملیات فرصت میدهد. اگر زمان تمام شود — expiration handler نتایج میانی را ذخیره میکند. پس از اتمام ذخیره، endBackgroundTask برای آزادسازی منابع فراخوانی میشود.
class DocumentManager {
private var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
func saveDocumentInBackground(document: Document) {
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
self.saveProgress(document)
self.endBackgroundTask()
}
DispatchQueue.global().async {
document.save()
self.endBackgroundTask()
}
}
private func endBackgroundTask() {
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
}
درخواستهای شبکه در پسزمینه نیاز به توجه ویژه دارند — expiration handler ممکن است درخواست را قبل از دریافت پاسخ قطع کند. از URLSession با dataTask استفاده کنید و قبل از ارسال backgroundTimeRemaining را بررسی کنید. اگر کمتر از ۵ ثانیه باقی مانده — ارسال را تا بیدار شدن بعدی برنامه به تعویق بیندازید.
func sendCriticalData(data: Data) {
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
// دادهها را برای ارسال مجدد ذخیره میکنیم
saveForRetry(data)
self.endBackgroundTask()
}
let task = URLSession.shared.dataTask(with: request) { _, _, error in
if error != nil {
saveForRetry(data)
}
self.endBackgroundTask()
}
task.resume()
}
برای عملیات طولانی، UIApplication.shared.backgroundTimeRemaining را ردیابی کنید. اگر مقدار از آستانه (۱۰ ثانیه) پایینتر رفت، عملیات جاری را قطع کرده و ذخیره نتایج میانی را شروع کنید. این امکان را میدهد که قبل از فراخوانی اجباری expiration handler کار را بهدرستی پایان دهید.
Background Task مکانیزم قدرتمندی است، اما استفاده نادرست از آن منجر به مشکلات باتری و عملکرد میشود. رعایت توصیههای Apple و روشهای تأییدشده جامعه به جلوگیری از خطاهای رایج و تضمین عملکرد پایدار برنامه کمک میکند.
Background Task را هر چه سریعتر پایان دهید. هر ثانیه اجرای پسزمینه انرژی باتری مصرف میکند. زمان بهینه — کمتر از ۵ ثانیه. اگر عملیات بیشتر طول میکشد — استفاده از BGTaskScheduler یا Background Modes را در نظر بگیرید. بدون نیاز واقعی، وظیفه را بهطور مصنوعی از طریق فراخوانیهای beginBackgroundTask طولانی نکنید.
UIBackgroundTaskIdentifier را به عنوان ویژگی کلاس یا ساختار ذخیره کنید. هرگز آن را به عنوان متغیر سراسری منتقل نکنید — این منجر به تداخل در وظایف متعدد میشود. پس از فراخوانی endBackgroundTask، شناسه را روی .invalid تنظیم کنید تا از تکمیل مضاعف جلوگیری شود.
در Xcode Simulator برنامه را از طریق دکمه Home (Command + Shift + H) به پسزمینه ببرید. از Debug — Simulate Background Fetch برای تست بیدارشدن پسزمینه استفاده کنید. برای شبیهسازی اتمام زمان، متغیر محیطی BACKGROUND_TASK_SIMULATE_EXPIRATION = YES را تنظیم کنید — expiration handler پس از ۵ ثانیه فراخوانی میشود.
// بررسی زمان باقیمانده قبل از شروع عملیات
let remaining = UIApplication.shared.backgroundTimeRemaining
guard remaining > 10.0 else {
// زمان کافی نیست — وظیفه را به تعویق بینداز
scheduleForNextLaunch()
return
}
// اجرای عملیات با کنترل زمان
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
saveProgress()
self.endBackgroundTask()
}
Expiration handler self را میگیرد — اگر backgroundTaskID به عنوان ویژگی همان شیء ذخیره شود، میتواند چرخه retain ایجاد کند. از [weak self] در بسته استفاده کنید یا شناسه را جداگانه ذخیره کنید. چرخه retain منجر به نشت حافظه میشود — شیء تا پایان برنامه آزاد نخواهد شد.
با عرضه iOS 13، Apple BGTaskScheduler را معرفی کرد — جایگزین مدرن API قدیمی Background Task. هر دو مکانیزم وظایف مشابهی را حل میکنند، اما BGTaskScheduler کنترل و انعطافپذیری بیشتری فراهم میکند. درک تفاوتها به انتخاب ابزار مناسب برای سناریوی خاص کمک میکند.
| ویژگی | Background Task | BGTaskScheduler |
|---|---|---|
| نسخه iOS | 4.0+ | 13.0+ |
| حداکثر زمان | ۳۰ ثانیه | ۳۰ ثانیه / ۱۰ دقیقه (processing) |
| شروع | didEnterBackground | برنامهریزی + سیستم |
| تضمین اجرا | فقط هنگام رفتن به پسزمینه | هر زمان مناسب برای سیستم |
| Expiration handler | بله، اجباری | بله، از طریق task.expirationHandler |
| اینترنت | نیاز در زمان شروع | از طریق requiresNetworkConnectivity |
| شارژ | نیاز ندارد | اختیاری برای processing |
beginBackgroundTask برای عملیات کوتاهمدتی مناسب است که باید بلافاصله هنگام رفتن به پسزمینه انجام شوند: ذخیره وضعیت، تکمیل درخواست شبکه، ذخیرهسازی داده. API ساده است و نیاز به پیکربندی Info.plist یا ثبت شناسهها ندارد. ایدهآل برای عملیاتی که کمتر از ۱۰ ثانیه طول میکشند.
BGTaskScheduler برای وظایفی مناسب است که میتوانند در هر زمان مناسب انجام شوند: همگامسازی دورهای، پاکسازی حافظه نهان، بهروزرسانی ویجتها. سیستم خود زمان بهینه را با توجه به رفتار کاربر و وضعیت باتری انتخاب میکند. برای عملیات طولانی (تا ۱۰ دقیقه) از BGProcessingTask استفاده کنید.
هر دو API را میتوان در یک برنامه استفاده کرد. Background Task — برای عملیات فوری هنگام رفتن به پسزمینه (ذخیره پیشنویس). BGTaskScheduler — برای بهروزرسانیهای برنامهریزیشده (همگامسازی هر ۶ ساعت). تقسیم مسئولیت امکان ذخیره صحیح دادهها و سرویسدهی پسزمینه با مصرف بهینه انرژی را فراهم میکند.
سوالات متداول
بله، beginBackgroundTask را میتوان در هر لحظه از کار برنامه فراخوانی کرد. با این حال، تخصیص زمان سیستم فقط پس از رفتن به پسزمینه شروع میشود. اگر برنامه در پیشزمینه است، فراخوانی beginBackgroundTask اثری ندارد — backgroundTimeRemaining DBL_MAX برمیگرداند و وظیفه هنگام رفتن به پسزمینه فعال میشود.
اگر endBackgroundTask فراخوانی نشود، سیستم همچنان برنامه را در پسزمینه فعال در نظر میگیرد. پس از ۳۰ ثانیه expiration handler فراخوانی میشود، اما اگر در آن هم endBackgroundTask نباشد — برنامه در حافظه باقی میماند و باتری مصرف میکند. در iOS 13+ سیستم چنین برنامهای را پس از ۳ دقیقه بهاجبار پایان میدهد.
زمان استاندارد ۳۰ ثانیه است. افزایش آن فقط از طریق Background Modes امکانپذیر است: Audio (پخش)، Location (موقعیتیابی)، Bluetooth (BLE). یا از طریق BGProcessingTask (iOS 13+) — تا ۱۰ دقیقه با شرایط شارژ و Wi-Fi. beginBackgroundTask به خودی خود راهی برای افزایش محدودیت فراهم نمیکند.
بله، iPadOS بهطور کامل از beginBackgroundTask با همان محدودیتهای iOS پشتیبانی میکند. در iPad با Stage Manager، برنامه میتواند بیشتر در حافظه بماند — سیستم به دلیل RAM بیشتر، برنامهها را کمتر تعلیق میکند. اما محدودیت ۳۰ ثانیه برای وظیفه پسزمینه باقی میماند.
دستگاه را به Xcode متصل کنید، برنامه را اجرا کنید، آن را به حداقل برسانید — لاگهای سیستم در کنسول ظاهر میشوند. از sysdiagnose برای جمعآوری لاگهای دقیق استفاده کنید: sysdiagnose را از دستگاه فراخوانی کنید (Volume Up + Down + Power). در Xcode Debug Navigator فعالیت وظایف پسزمینه را ردیابی کنید.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید