- Published on
SwiftUI-da Timer va onReceive — Publisher-Subscriber amaliyoti
- Authors
- Name
- ShoxruxC
- @iOSdasturchi
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?
| Misol | Ishlatilishi |
|---|---|
| Joriy vaqt | Soat ekrani, real-time ma'lumot |
| Countdown | O'yin, test vaqti, taklif muddati |
| Kelajakka countdown | "24 soat qoldi" kabi countdown |
| Loading indikatori | Ma'lumot yuklanayotganda |
| Avtomatik karusel | Banner, rasm slayderi |