.task { } — এটি কী, async মডিফায়ার এবং View-এ ডেটা লোডিং

লেখক: IT Sectr প্রকাশিত: 2026-06-26 পড়ার সময়: 9 মিনিট

.task { } হল SwiftUI-তে iOS 15-এ প্রবর্তিত একটি মডিফায়ার যা View প্রদর্শিত হলে একটি অ্যাসিঙ্ক্রোনাস অপারেশন শুরু করে এবং View অদৃশ্য হলে স্বয়ংক্রিয়ভাবে তা বাতিল করে। .onAppear-এর বিপরীতে, যা বাতিল করার ক্ষমতা ছাড়াই সিঙ্ক্রোনাস কোড নির্বাহ করে, .task async/await কনটেক্সটের সাথে কাজ করে এবং View-এর জীবনচক্র বিবেচনা করে: View অদৃশ্য হলে, SwiftUI তৈরি করা Task-এ cancel() কল করে। এটি মেমরি লিক এবং View-এর আর আপডেটের প্রয়োজন না হওয়া সত্ত্বেও অপারেশন নির্বাহ হওয়া প্রতিরোধ করে। Apple WWDC Session 10132 — Meet async/await in SwiftUI (2024) অনুসারে, .task হল SwiftUI-তে ডেটা লোড করার পছন্দের উপায় কারণ এটি Structured Concurrency-এর সাথে নিরাপদে কাজ করে এবং অ্যাসিঙ্ক্রোনাস অপারেশনের জীবনকাল স্বয়ংক্রিয়ভাবে পরিচালনা করে।

মূল পয়েন্ট

  • .task { } — SwiftUI মডিফায়ার View প্রদর্শিত হলে অ্যাসিঙ্ক্রোনাস ডেটা লোডিংয়ের জন্য, iOS 15 থেকে উপলব্ধ।
  • স্বয়ংক্রিয় বাতিলকরণ — View অদৃশ্য হলে SwiftUI Task বাতিল করে, মেমরি লিক প্রতিরোধ করে।
  • async/await কনটেক্সট — .task-এর ভিতরে DispatchQueue বা Combine ছাড়াই async কল উপলব্ধ।
  • .task(id:) — শনাক্তকারী সহ সংস্করণ যা নির্দিষ্ট মান পরিবর্তন হলে টাস্ক পুনরায় শুরু করে।
  • Structured Concurrency — .task সমান্তরাল অপারেশনের জন্য Structured Concurrency এবং TaskGroup সমর্থন করে।

SwiftUI-তে .task { } কী

.task { } হল একটি View মডিফায়ার যা View স্ক্রিনে প্রদর্শিত হলে async কনটেক্সটে একটি Task তৈরি করে। SwiftUI প্রদত্ত ক্লোজারটি ব্যাকগ্রাউন্ড থ্রেডে নির্বাহ করে, মূল থ্রেডটি UI অপারেশনের জন্য মুক্ত রাখে। যখন View অদৃশ্য হয়, SwiftUI Structured Concurrency মেকানিজমের মাধ্যমে স্বয়ংক্রিয়ভাবে Task বাতিল করে — এটি নিশ্চিত করে যে অ্যাসিঙ্ক্রোনাস অপারেশন তার ফলাফলের আর প্রয়োজন না থাকলেও নির্বাহ হতে থাকে না।

Apple — Swift Programming Language (2025) অনুসারে, .task Swift 5.5-এ প্রবর্তিত Structured Concurrency-এর ধারণা ব্যবহার করে। প্রতিটি .task প্যারেন্ট View-এর টাস্কের অধীনে একটি চাইল্ড টাস্ক তৈরি করে। যদি প্যারেন্ট টাস্ক বাতিল হয় (View অদৃশ্য হয়), তবে সমস্ত চাইল্ড টাস্কও স্বয়ংক্রিয়ভাবে বাতিল হয়। এটি DispatchWorkItem বা AnyCancellable-এর রেফারেন্স ম্যানুয়ালি সংরক্ষণের তুলনায় অ্যাসিঙ্ক্রোনাস অপারেশনের জীবনচক্র পরিচালনাকে মৌলিকভাবে সহজ করে।

@State + .onAppear-এ ম্যানুয়াল কলের ঐতিহ্যগত পদ্ধতির বিপরীতে, .task-এর পরবর্তী বাতিলের জন্য Task-এর রেফারেন্স সংরক্ষণের প্রয়োজন হয় না। SwiftUI এটি স্বয়ংক্রিয়ভাবে করে, বয়লারপ্লেট কোড হ্রাস করে এবং টাস্ক বাতিল করতে ভুলে যাওয়ার ঝুঁকি দূর করে।

swift
struct ArticlesView: View {
    @State var articles: [Article] = []
    @State var error: Error?
    
    var body: some View {
        List(articles) { article in
            Text(article.title)
        }
        .task {
            do {
                articles = await APIClient().fetchArticles()
            } catch {
                self.error = error
            }
        }
    }
}

.task বনাম .onAppear: মূল পার্থক্য

অনেক ডেভেলপার .onAppear-এ ডেটা লোড করতে অভ্যস্ত, কিন্তু async/await এবং .task-এর আগমনে এই পদ্ধতি পুরনো হয়ে গেছে। .onAppear কোড সিঙ্ক্রোনাসভাবে নির্বাহ করে — .onAppear-এর ভিতরে অ্যাসিঙ্ক্রোনাস অপারেশনের জন্য, কলটি Task { }-এ মোড়ানো এবং সম্ভাব্য বাতিলের জন্য ম্যানুয়ালি তার রেফারেন্স রাখা প্রয়োজন। .task এটি স্বয়ংক্রিয়ভাবে করে।

বৈশিষ্ট্য.task { }.onAppear
Async কনটেক্সটঅন্তর্নির্মিত async/awaitTask { } র্যাপার প্রয়োজন
স্বয়ংক্রিয় বাতিলহ্যাঁ, View অদৃশ্য হলেনা, ম্যানুয়ালি বাস্তবায়ন করতে হবে
Structured Concurrencyসমর্থন করেসমর্থন করে না
পুনরায় সক্রিয়করণশুধুমাত্র id পরিবর্তনেপ্রতিবার View প্রদর্শিত হলে
Apple সুপারিশপছন্দের উপায়সিঙ্ক্রোনাস অপারেশনের জন্য

.onAppear এখনও সিঙ্ক্রোনাস অপারেশনের জন্য useful — উদাহরণস্বরূপ, লগিং বা প্রাথমিক UI সেটআপ। কিন্তু অ্যাসিঙ্ক্রোনাস ডেটা লোডিং, নেটওয়ার্ক অনুরোধ, ডাটাবেস বা ফাইল সিস্টেম অপারেশনের জন্য .task ব্যবহার করুন। এটি আর্কিটেকচারের দৃষ্টিকোণ থেকে নিরাপদ এবং পরিষ্কার।

swift
// ❌ পুরনো পদ্ধতি: .onAppear-এ বাতিল ছাড়া Task
var loadTask: Task<Void, Never>?
func body() { var body: some View { Text("") }
    .onAppear {
        loadTask = Task { await loadData() }
    }
    .onDisappear { loadTask?.cancel() }

// ✅ আধুনিক পদ্ধতি: .task বাতিল পরিচালনা করে
func body() { var body: some View { Text("") }
    .task { await loadData() }

.task(id:) — ডেটা পরিবর্তনে পুনরায় শুরু

.task(id:) মডিফায়ার একটি অতিরিক্ত প্যারামিটার — শনাক্তকারী গ্রহণ করে। যখন শনাক্তকারীর মান পরিবর্তন হয়, SwiftUI বর্তমান টাস্ক বাতিল করে এবং নতুন শনাক্তকারী সহ একটি নতুন টাস্ক শুরু করে। এটি সেই স্ক্রিনগুলির জন্য আদর্শ যেখানে ডেটা একটি নির্বাচিত প্যারামিটারের উপর নির্ভর করে — উদাহরণস্বরূপ, বিভাগ অনুযায়ী নিবন্ধের তালিকা বা ID অনুযায়ী পণ্যের বিবরণ।

swift
struct CategoryView: View {
    let categoryId: Int
    @State var items: [Item] = []
    
    var body: some View {
        List(items) { item in
            Text(item.name)
        }
        .task(id: categoryId) {
            await loadItems(for: categoryId)
        }
    }
    
    func loadItems(for id: Int) async {
        do {
            items = await APIClient().fetchItems(categoryId: id)
        } catch {
            // ত্রুটি সামলান
        }
    }
}

যখন categoryId পরিবর্তন হয়, SwiftUI পূর্ববর্তী অনুরোধ বাতিল করে এবং নতুনটি শুরু করে। এটি দ্রুত বিভাগ স্যুইচিংয়ের সময় বিশেষভাবে গুরুত্বপূর্ণ — পুরনো অনুরোধগুলি স্টেট আপডেটের জন্য নতুনগুলির সাথে প্রতিযোগিতা করবে না। .task(id:) ছাড়া, আপনাকে .onChange-এর মাধ্যমে ম্যানুয়ালি পরিবর্তন ট্র্যাক করতে এবং Task ম্যানুয়ালি পরিচালনা করতে হবে।

টাস্ক বাতিলকরণ এবং isCancelled পরীক্ষা

যদিও .task View অদৃশ্য হলে টাস্ক স্বয়ংক্রিয়ভাবে বাতিল করে, অ্যাসিঙ্ক্রোনাস অপারেশনকে নিজেই সহযোগিতামূলকভাবে বাতিল পরীক্ষা করতে হবে। Swift একটি সহযোগিতামূলক বাতিল মডেল ব্যবহার করে — Task.cancel() জোর করে নির্বাহ বন্ধ করে না, বরং শুধুমাত্র isCancelled ফ্ল্যাগ সেট করে। টাস্কের ভিতরের কোডের সময়ে সময়ে এই ফ্ল্যাগ পরীক্ষা করা উচিত।

swift
struct LoadingView: View {
    @State var progress: Double = 0
    
    var body: some View {
        ProgressView(value: progress)
            .task {
                for i in 0..<100 {
                    // বাতিল পরীক্ষা করুন
                    try Task.checkCancellation()
                    
                    await Task.sleep(nanoseconds: 50_000_000)
                    progress = Double(i + 1) / 100.0
                }
            }
    }
}

Task.checkCancellation() CancellationError নিক্ষেপ করে যদি টাস্ক বাতিল করা হয়। এটি পরীক্ষার সবচেয়ে সহজ উপায় — এটি যেকোনো async কনটেক্সটে কাজ করে। বিকল্প হল ব্যয়বহুল অপারেশনের আগে Task.isCancelled ম্যানুয়ালি পরীক্ষা করা। URLSession-এর জন্য, নেটওয়ার্ক অনুরোধ টাস্ক বাতিল হলে স্বয়ংক্রিয়ভাবে বাতিল হয়, কারণ URLSession মূলত Structured Concurrency সমর্থন করে।

.task-এর ব্যবহারিক উদাহরণ

.task অনেক পরিস্থিতির জন্য উপযুক্ত: সাধারণ JSON লোডিং থেকে TaskGroup-এর সাথে জটিল সমান্তরাল অপারেশন পর্যন্ত। আসুন তিনটি সাধারণ ব্যবহারের দৃষ্টান্ত দেখি।

ত্রুটি পরিচালনার সাথে লোডিং

swift
struct ProfileView: View {
    @State var profile: Profile?
    @State var isLoading = true
    
    var body: some View {
        Group {
            if isLoading {
                ProgressView()
            } else if let profile {
                Text(profile.name)
            } else {
                Text("লোড করতে ব্যর্থ")
            }
        }
        .task {
            defer { isLoading = false }
            do {
                profile = await APIClient().fetchProfile()
            } catch {
                // প্রোফাইল nil থাকে
            }
        }
    }
}

TaskGroup-এর সাথে সমান্তরাল লোডিং

swift
struct DashboardView: View {
    @State var stats: DashboardStats?
    
    var body: some View {
        Text("ড্যাশবোর্ড")
            .task {
                stats = await Task {
                    await withThrowingTaskGroup { group in
                        group.addTask { await API().fetchUsers() }
                        group.addTask { await API().fetchOrders() }
                        group.addTask { await API().fetchRevenue() }
                        
                        return DashboardStats(
                            users: try await group.next(),
                            orders: try await group.next(),
                            revenue: try await group.next()
                        )
                    }
                }.value
            }
    }
}

.task-এ সাধারণ ভুল

সবচেয়ে সাধারণ ভুল হল মূল থ্রেডে সুইচ না করেই .task-এর ভিতরে UI বৈশিষ্ট্য পরিবর্তন করা। যদিও SwiftUI async কনটেক্সটে @State পরিবর্তন করার সময় স্বয়ংক্রিয়ভাবে মূল থ্রেডে আপডেট ফিরিয়ে দেয়, .task-এর ভিতরে UIKit উপাদানগুলির সরাসরি হেরফের ক্র্যাশের কারণ হতে পারে।

  • try/catch ভুলে যাওয়া — .task স্বয়ংক্রিয়ভাবে ত্রুটি পরিচালনা করে না। সমস্ত থ্রোয়িং ফাংশন do/catch-এ মোড়ানো আবশ্যক, অন্যথায় অ্যাপ ক্র্যাশ হবে।
  • ডেটা রেস — যদি একাধিক .task(id:) ভিন্ন id দিয়ে শুরু হয় এবং একই স্টেট আপডেট করে, ডেটা রেস ঘটতে পারে। ভিন্ন ডেটা উৎসের জন্য পৃথক বৈশিষ্ট্য ব্যবহার করুন।
  • দীর্ঘ সিঙ্ক্রোনাস অপারেশন — .task সিঙ্ক্রোনাস কোডকে অ্যাসিঙ্ক্রোনাস করে না। যদি .task-এর ভিতরে ভারী সিঙ্ক্রোনাস কাজ থাকে, তবে এটি Task.detached-এ মোড়ান বা একটি পৃথক async পদ্ধতিতে সরান।
  • CancellationError উপেক্ষা করা — Task.checkCancellation() পরীক্ষা করার সময়, CancellationError উপরের দিকে প্রচার করা উচিত, দমন করা নয়। বাতিল দমন করলে মেমরি লিক হতে পারে।
swift
// ❌ ত্রুটি: কোনো ত্রুটি পরিচালনা নেই
.task {
    let data = await fetchData() // ত্রুটিতে ক্র্যাশ!
    items = data
}

// ✅ সঠিক: do/catch
.task {
    do {
        items = await fetchData()
    } catch {
        errorMessage = error.localizedDescription
    }
}

সচরাচর জিজ্ঞাসিত প্রশ্ন

.task এবং .onAppear-এ Task { } ব্যবহারের মধ্যে পার্থক্য কী?

.task স্বয়ংক্রিয়ভাবে View অদৃশ্য হলে টাস্ক বাতিল করে এবং Structured Concurrency সমর্থন করে। .onAppear-এ Task { }-এর জন্য টাস্কের রেফারেন্স ম্যানুয়ালি রাখা এবং .onDisappear-এ cancel() কল করা প্রয়োজন। .task পড়তেও সহজ — এটি স্পষ্টভাবে নির্দেশ করে যে ডেটা লোডিং View-এর জীবনচক্রের অংশ।

.task কি publisher-এ সাবস্ক্রাইব করতে ব্যবহার করা যাবে?

হ্যাঁ, AsyncSequence বা AsyncStream-এ সাবস্ক্রাইব করতে, .task-এর ভিতরে for await value in publisher.values ব্যবহার করুন। এটি Publisher.values এক্সটেনশনের মাধ্যমে async/await এবং Combine উভয়ের সাথেই কাজ করে। View অদৃশ্য হলে, পুনরাবৃত্তি স্বয়ংক্রিয়ভাবে শেষ হবে এবং সাবস্ক্রিপশন বাতিল হবে।

.task TabView-এর সাথে কীভাবে কাজ করে — ট্যাব সুইচ করলে কি টাস্ক পুনরায় শুরু হয়?

হ্যাঁ, যদি TabView-এর ভিতরে View প্রতিটি সুইচে পুনরায় তৈরি হয়। iOS 18 থেকে, TabView Views মেমোরিতে রাখতে পারে — এই ক্ষেত্রে .task পুনরায় শুরু হয় না। যদি প্রতিটি ট্যাব সুইচে ডেটা পুনরায় লোড করার প্রয়োজন হয়, ট্যাব শনাক্তকারী সহ .task(id:) ব্যবহার করুন।

.task সহ View অনুরোধ শেষ হওয়ার আগে অদৃশ্য হলে কী হবে?

SwiftUI View অদৃশ্য হলে টাস্ক বাতিল করবে। যদি URLSession অনুরোধ টাস্কের ভিতরে ছিল, তাও বাতিল হবে। যদি টাস্ক সহযোগিতামূলক বাতিল সমর্থন না করে (উদাহরণস্বরূপ, isCancelled পরীক্ষা না করে), এটি চলতে থাকবে, কিন্তু এর ফলাফল স্টেটে প্রযোজ্য হবে না কারণ View আর বিদ্যমান নেই।

একটি View-তে কি একাধিক .task মডিফায়ার ব্যবহার করা যাবে?

হ্যাঁ, আপনি একটি View-তে একাধিক .task মডিফায়ার যোগ করতে পারেন। প্রতিটি একটি স্বাধীন টাস্ক তৈরি করে। এটি বিভিন্ন ডেটা উৎস পৃথক করার জন্য useful: প্রোফাইল লোড করার জন্য একটি .task, WebSocket-এ সাবস্ক্রাইব করার জন্য দ্বিতীয়টি, জিওলোকেশন মনিটর করার জন্য তৃতীয়টি।

সারসংক্ষেপ

  • .task { } — View অদৃশ্য হলে স্বয়ংক্রিয় বাতিল সহ অ্যাসিঙ্ক্রোনাস অপারেশনের জন্য SwiftUI মডিফায়ার।
  • async/await সমর্থন — .task-এর ভিতরে Task র্যাপার ছাড়াই পূর্ণ async কনটেক্সট উপলব্ধ।
  • .task(id:) — শনাক্তকারী পরিবর্তনে টাস্ক পুনরায় শুরু করে, ম্যানুয়াল .onChange প্রতিস্থাপন করে।
  • সহযোগিতামূলক বাতিল — টাস্কের ভিতরে বাতিল পরীক্ষা করতে Task.checkCancellation() ব্যবহার করুন।
  • Structured Concurrency — .task চাইল্ড টাস্ক বাতিল সহ TaskGroup এবং সমান্তরাল অপারেশন সমর্থন করে।
  • .onAppear-এর বিকল্প — অ্যাসিঙ্ক্রোনাস ডেটা লোডিংয়ের জন্য .onAppear + Task + .onDisappear প্যাটার্নের বদলে .task ব্যবহার করুন।
  • ত্রুটি পরিচালনা — ক্র্যাশ প্রতিরোধে .task-এর ভিতরে সমস্ত async কল do/catch-এ মোড়ানো আবশ্যক।

আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব

IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।

প্রকল্প নিয়ে আলোচনা করুন

আরও পড়ুন