Published on

SwiftUI-da Timer va onReceive — Publisher-Subscriber amaliyoti

Authors

Bu videoda Timer va onReceive ko'rib chiqiladi. Timer — aslida Combine-dagi Publisher: har N soniyada qiymat chiqaradi. onReceive esa shu publisherga subscribe qilish — har yangi qiymat chiqarilganda amal bajarish imkonini beradi.


Timer yaratish

// Har 1 soniyada Date qiymat chiqaruvchi publisher
let timer = Timer.publish(
    every: 1,           // necha soniyada bir
    on: .main,          // qaysi thread — UI uchun main
    in: .common         // run loop mode
)
.autoconnect()          // view yuklanganda avtomatik boshlash

.autoconnect() — view yaratilishi bilanoq timer boshlanadi. Bo'lmasizm, .connect() qo'lda chaqirilishi kerak edi.


1-misol: Joriy vaqtni ko'rsatish

struct TimerBootcamp: View {

    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

    @State var currentDate: Date = Date()

    // Chiroyli vaqt formati
    var dateFormatter: DateFormatter {
        let formatter = DateFormatter()
        formatter.timeStyle = .medium   // 6:09:35 PM
        // formatter.dateStyle = .medium  // Sana ham kerak bo'lsa
        return formatter
    }

    var body: some View {
        ZStack {
            RadialGradient(
                gradient: Gradient(colors: [Color.purple, Color.purple.opacity(0.6)]),
                center: .center,
                startRadius: 5,
                endRadius: 500
            )
            .ignoresSafeArea()

            Text(dateFormatter.string(from: currentDate))
                .font(.system(size: 100, weight: .semibold, design: .rounded))
                .foregroundColor(.white)
                .lineLimit(1)
                .minimumScaleFactor(0.1)
        }
        // Timer-ga subscribe qilish
        .onReceive(timer) { value in
            currentDate = value  // har 1 soniyada yangilanadi
        }
    }
}

onReceive — berilgan publisherga subscribe qiladi. Timer Date qiymati chiqaradi — shuning uchun value tipi Date.


2-misol: Oddiy countdown sanagichi

struct TimerBootcamp: View {

    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

    @State var count: Int = 10
    @State var finishedText: String? = nil

    var body: some View {
        ZStack {
            // fon ...

            Text(finishedText ?? "\(count)")
                .font(.system(size: 100, weight: .semibold, design: .rounded))
                .foregroundColor(.white)
        }
        .onReceive(timer) { _ in
            // Date qiymat kerak emas — _ bilan e'tiborsiz qoldiriladi
            if count <= 1 {
                finishedText = "Wow!"
            } else {
                count -= 1
            }
        }
    }
}

_ — publisherdan kelayotgan qiymat kerak bo'lmasa e'tiborsiz qoldiriladi. Bu holda faqat "har 1 soniyada biror narsa qil" mantiq ishlatiladi.


3-misol: Kelajak sanagacha countdown

Ko'p ilovalarda — "24 soat ichida vazifani bajaring" kabi countdown. Calendar bilan qolgan vaqtni hisoblash:

struct TimerBootcamp: View {

    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

    @State var timeRemaining: String = ""

    // Kelajak sana — hozirdan 24 soat keyin
    let futureDate: Date = Calendar.current.date(
        byAdding: .day,
        value: 1,
        to: Date()
    ) ?? Date()

    func updateTimeRemaining() {
        let remaining = Calendar.current.dateComponents(
            [.hour, .minute, .second],
            from: Date(),
            to: futureDate
        )
        let hour   = remaining.hour   ?? 0
        let minute = remaining.minute ?? 0
        let second = remaining.second ?? 0

        timeRemaining = "\(hour):\(minute):\(second)"
    }

    var body: some View {
        ZStack {
            // fon ...

            Text(timeRemaining)
                .font(.system(size: 100, weight: .semibold, design: .rounded))
                .foregroundColor(.white)
                .lineLimit(1)
                .minimumScaleFactor(0.1)
        }
        .onReceive(timer) { _ in
            updateTimeRemaining()
        }
    }
}

Calendar.current.dateComponents — ikkita sana orasidagi farqni soat/daqiqa/soniyada qaytaradi. Boshqa xususiyatlar ham qo'shish mumkin: byAdding: .hour — soat qo'shish, byAdding: .minute — daqiqa.


4-misol: Animatsion yuklanish indikatori

Timer-ni animatsiya bilan birlashtirish — chiroyli loading dots effekti:

struct TimerBootcamp: View {

    let timer = Timer.publish(every: 0.5, on: .main, in: .common).autoconnect()

    @State var count: Int = 0

    var body: some View {
        ZStack {
            // fon ...

            HStack(spacing: 15) {
                Circle()
                    .offset(y: count == 1 ? -20 : 0)
                Circle()
                    .offset(y: count == 2 ? -20 : 0)
                Circle()
                    .offset(y: count == 3 ? -20 : 0)
            }
            .foregroundColor(.white)
            .frame(width: 150)
        }
        .onReceive(timer) { _ in
            withAnimation(.easeInOut(duration: 0.5)) {
                count = count == 3 ? 0 : count + 1
            }
        }
    }
}

Har 0.5 soniyada count 0 → 1 → 2 → 3 → 0 aylanadi. Har bir doira o'z count qiymatida ko'tariladi — ketma-ket ko'tarilish effekti hosil bo'ladi.


5-misol: Avtomatik karusel (TabView bilan)

Tik-Tok, ilovalar bosh sahifasidagi banner slider kabi — har 3 soniyada o'z-o'zidan suriluvchi karusel:

struct TimerBootcamp: View {

    let timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect()

    @State var count: Int = 1

    var body: some View {
        ZStack {
            // fon ...

            TabView(selection: $count) {
                Rectangle().foregroundColor(.red).tag(1)
                Rectangle().foregroundColor(.blue).tag(2)
                Rectangle().foregroundColor(.green).tag(3)
                Rectangle().foregroundColor(.orange).tag(4)
                Rectangle().foregroundColor(.pink).tag(5)
            }
            .tabViewStyle(PageTabViewStyle())
            .frame(height: 200)
        }
        .onReceive(timer) { _ in
            withAnimation(.default) {
                count = count == 5 ? 1 : count + 1
            }
        }
    }
}

TabView(selection: $count)count o'zgarganda ko'rsatiladigan tab avtomatik o'zgaradi. Har 3 soniyada count 1→2→3→4→5→1 aylanadi. Haqiqiy ilovada to'rtburchaklar o'rniga rasmlar yoki custom view-lar ishlatiladi.


Timer — aslida Publisher

// Timer = Publisher
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

// onReceive = Subscribe
.onReceive(timer) { value in
    // har 1 soniyada bu kod ishlaydi
}

Timer-ning asosiy g'oyasi: u Combine-dagi Publisher. Vaqtga bog'liq har qanday amal uchun — countdown, animatsiya, avtomatik yangilanish — Timer + onReceive kombinatsiyasi eng qulay yechim.


Xulosa — qaysi misol qachon?

MisolIshlatilishi
Joriy vaqtSoat ekrani, real-time ma'lumot
CountdownO'yin, test vaqti, taklif muddati
Kelajakka countdown"24 soat qoldi" kabi countdown
Loading indikatoriMa'lumot yuklanayotganda
Avtomatik karuselBanner, rasm slayderi
Buy mea coffee