CBPeripheral: bu nima, metodlari va iOS-da BLE-periferiyani boshqarish

Muallif: IT Sectr Nashr etilgan: 2026-07-16 O'qish vaqti: 10 daq

CBPeripheral — iOS-da uzoqdagi BLE qurilmasini ifodalovchi Core Bluetooth framework sinfi. Har bir CBPeripheral obyekti UUID, nom, RSSI va ulangan BLE qurilmasining GATT servislar iyerarxiyasini inkapsulatsiya qiladi. Dasturchi periferiya bilan faqat CBPeripheral orqali o'zaro aloqa qiladi: servislarni discovery qilish (discoverServices:), xarakteristikalarni o'qish (readValueForCharacteristic:), ma'lumotlarni yozish (writeValue:forCharacteristic:type:) va bildirishnomalarga obuna bo'lish (setNotifyValue:forCharacteristic:). Apple Developer, 2026 ma'lumotlariga ko'ra, CBPeripheral — CBCentralManager tomonidan qurilma topilganda yoki ulanganda qaytariladigan, BLE-periferiya bilan barcha operatsiyalar uchun markaziy obyektdir.

Asosiy ma'lumotlar

  • CBPeripheral — iOS-da uzoqdagi BLE qurilmasi bilan ishlash uchun Core Bluetooth sinfi
  • GATT iyerarxiyasi — Peripheral servislarni (CBService), servislar xarakteristikalarni (CBCharacteristic), xarakteristikalar deskriptorlarni (CBDescriptor) o'z ichiga oladi
  • Discovery — qurilmaning GATT strukturasini olish uchun discoverServices: va discoverCharacteristics:forService:
  • O'qish va yozish — readValueForCharacteristic: va writeValue:forCharacteristic:type: tasdiqlash bilan (withResponse) yoki tasdiqlashsiz (withoutResponse)
  • Bildirishnomalar — setNotifyValue:forCharacteristic: BLE qurilmasi xarakteristikalaridagi o'zgarishlarga obunani faollashtiradi

CBPeripheral nima: mohiyati va vazifasi

CBPeripheral — iOS ilovasida uzoqdagi BLE qurilmasini ifodalovchi obyektdir. iPhone-ning mahalliy Bluetooth adapterini boshqaradigan CBCentralManager-dan farqli o'laroq, CBPeripheral tashqi periferik qurilmani modellashtiradi: sensor, fitness treker, mayoq, tibbiy asbob. Har bir CBPeripheral nusxasi noyob identifikator (UUID) o'z ichiga oladi, u ulanish seanslari orasida saqlanadi — Apple UUID-ni tizim Bonding orqali ma'lum bir qurilma bilan bog'laydi.

CBPeripheral to'g'ridan-to'g'ri init orqali yaratilmaydi. Core Bluetooth framework-i CBPeripheral obyektini ikkita ssenariyda qaytaradi: scanForPeripheralsWithServices: orqali qurilma topilganda (delegat didDiscoverPeripheral) va retrievePeripheralsWithIdentifiers: orqali oldindan ma'lum qurilmaga ulanganda. Obyekt olingandan so'ng, dasturchi CBCentralManager-da connectPeripheral: chaqiradi, shundan so'ng CBPeripheral GATT operatsiyalari uchun mavjud bo'ladi.

CBPeripheral hayot aylanishi oltita holatni o'z ichiga oladi: disconnected (boshlang'ich), connecting (connect chaqiruvidan so'ng), connected (didConnectPeripheral-dan so'ng), discovering (discoverServices chaqiruvi vaqtida), discovered (servislar olingandan so'ng) va disconnecting (cancelPeripheralConnection-dan so'ng). Har bir holat CBPeripheralDelegate delegati orqali kuzatiladi — iOS-dagi har bir BLE ilovasi uchun majburiy protokol.

CBPeripheral va GATT iyerarxiyasi: servislar, xarakteristikalar, deskriptorlar

CBPeripheral uch darajadan iborat iyerarxik GATT strukturasini saqlaydi. Ildiz darajasi — CBService massivi (servislar), har bir servis CBCharacteristic massivi (xarakteristikalar), har bir xarakteristika CBDescriptor massivi (deskriptorlar) o'z ichiga oladi. Bu model Bluetooth GATT spetsifikatsiyasiga to'liq mos keladi: servis — qurilmaning funktsiyasi (masalan, „Heart Rate Service“), xarakteristika — aniq qiymat (yurak urishi 72 bpm), deskriptor — xarakteristikaning metama'lumotlari (o'lchov birliklari, bildirishnomalar konfiguratsiyasi).

DarajaCore Bluetooth sinfiTavsif
ServisCBServiceO'zaro bog'liq xarakteristikalar mantiqiy guruhi, UUID (16-bit, 32-bit yoki 128-bit) bilan identifikatsiya qilinadi
XarakteristikaCBCharacteristicAniq ma'lumot qiymati, o'qish, yozish, bildirishnomani qo'llab-quvvatlaydi
DeskriptorCBDescriptorXarakteristikaning metama'lumotlari: CCCD mijoz konfiguratsiyasi, User Description, Presentation Format

Standart BLE-servislar Bluetooth SIG da ro'yxatdan o'tgan: Heart Rate Service (UUID 180D), Battery Service (180F), Device Information (180A), Blood Pressure (1810). Maxsus servislar uchun 128-bit UUID ishlatiladi (masalan, E20A39F4-73F5-4BC4-A12F-17D1AD07A961). iOS standart UUID-larni avtomatik taniydi va odam o'qiy oladigan nomlarni ko'rsatadi; maxsus UUID-lar hex formatida ko'rsatiladi.

CBPeripheral ulangandan so'ng, uning iyerarxiyasi bo'sh — servislar va xarakteristikalar yuklanmagan. Dasturchi servislarni olish uchun discoverServices: chaqirishi kerak, so'ngra har bir servis uchun discoverCharacteristics:forService: chaqirishi kerak. Agar servis qo'shilgan servislarni (includedServices) o'z ichiga olsa, qo'shimcha ravishda discoverIncludedServices:forService: chaqiriladi. Faqat discovery iyerarxiyasi tugallangandan so'ng, CBPeripheral to'ldiriladi va o'qish/yozish uchun mavjud bo'ladi.

Servislar va xarakteristikalarni discovery qilish: metodlar va delegatlar

Discovery (topish) CBPeripheral GATT strukturasining — har qanday o'qish yoki yozish operatsiyalaridan oldin majburiy qadamdir. discoverServices: metodi qurilmaning barcha servislarining asinxron qidiruvini boshlaydi. Agar nil uzatilsa, barcha servislar topiladi; agar CBUUID massivi uzatilsa — faqat ko'rsatilgan UUID-li servislar (vaqt optimizatsiyasi). Natija peripheral:didDiscoverServices: delegatiga keladi — CBPeripheral obyekti services xususiyatini CBService massivi bilan to'ldiradi.

Servislar olingandan so'ng, har bir CBService uchun discoverCharacteristics:forService: chaqirilishi kerak. Xuddi shunday, nil — barcha xarakteristikalar, CBUUID massivi — faqat ko'rsatilganlar. Natija: peripheral:didDiscoverCharacteristicsForService:error:. Bu bosqichda CBCharacteristic ruxsat etilgan operatsiyalarni aniqlaydigan xususiyatlarni (properties: .read, .write, .notify, .indicate) oladi.

swift
import CoreBluetooth

extension BLEViewController: CBPeripheralDelegate {

    // 1. Servis discovery si
    func peripheral(_ peripheral: CBPeripheral,
                     didDiscoverServices error: Error?) {
        guard let services = peripheral.services else { return }

        for service in services {
            // Har bir servis uchun xarakteristikalarni so'rash
            peripheral.discoverCharacteristics(nil, for: service)
        }
    }

    // 2. Xarakteristika discovery si
    func peripheral(_ peripheral: CBPeripheral,
                     didDiscoverCharacteristicsFor service: CBService,
                     error: Error?) {
        guard let characteristics = service.characteristics else { return }

        for characteristic in characteristics {
            if characteristic.properties.contains(.read) {
                peripheral.readValue(for: characteristic)
            }
            if characteristic.properties.contains(.notify) {
                peripheral.setNotifyValue(true, for: characteristic)
            }
        }
    }

    // 3. Qiymatni o'qish
    func peripheral(_ peripheral: CBPeripheral,
                     didUpdateValueFor characteristic: CBCharacteristic,
                     error: Error?) {
        guard let data = characteristic.value,
              let value = String(data: data, encoding: .utf8)
        else { return }
        print("Characteristic value: \(value)")
    }
}

Misolda CBPeripheralDelegate-ning uchta majburiy topish metodi amalga oshirilgan. didDiscoverServices barcha topilgan servislarni aylanib chiqadi va xarakteristikalarni so'raydi. didDiscoverCharacteristicsForService har bir xarakteristikaning xususiyatlarini tekshiradi: .read uchun readValue chaqiradi, .notify uchun — setNotifyValue(true). didUpdateValueForCharacteristic metodi joriy qiymatni Data formatida oladi.

Xarakteristikalarni o'qish va yozish: withResponse va withoutResponse

Qiymatlarni o'qish CBCharacteristic readValueForCharacteristic: metodi bilan amalga oshiriladi. Natija asinxron ravishda peripheral:didUpdateValueForCharacteristic:error: da keladi. Muhim: qurilmada keshlangan qiymat bo'lishi mumkin (characteristic.value discovery-dan so'ng darhol mavjud), ammo joriy qiymatni olish uchun readValue chaqiruvi majburiydir. iOS energiya samaradorligi uchun qiymatlarni keshlashi mumkin — readValue keshlarni yangilaydi.

Qiymatlarni yozish writeValue:forCharacteristic:type: metodi bilan amalga oshiriladi. type parametri yozish turini aniqlaydi: .withResponse (CBCharacteristicWriteWithResponse) — qurilma didWriteValueForCharacteristic orqali yozishni tasdiqlaydi; .withoutResponse (CBCharacteristicWriteWithoutResponse) — tasdiqlashsiz yozish, maksimal tezlik, lekin yetkazib berish kafolatisiz. BLE spetsifikatsiyasi MTU (Maximum Transmission Unit) ni cheklaydi: BLE 4.0 uchun 23 baytgacha, BLE 5.0+ uchun 251 baytgacha. MTU dan katta ma'lumotlar uchun dastur darajasida fragmentatsiya talab qilinadi.

swift
// CBPeripheral xarakteristika o'qish va yozish
class BLEService {

    private let peripheral: CBPeripheral
    private let serviceUUID = CBUUID(string: "180D")
    private let charUUID = CBUUID(string: "2A37")

    init(peripheral: CBPeripheral) {
        self.peripheral = peripheral
    }

    // Tasdiqlash bilan o'qish
    func readHeartRate() {
        guard let service = peripheral.services?.first(where: { $0.uuid == serviceUUID }),
              let characteristic = service.characteristics?.first(where: { $0.uuid == charUUID })
        else { return }
        peripheral.readValue(for: characteristic)
    }

    // Tasdiqlash bilan yozish (withResponse)
    func writeWithResponse(data: Data) {
        guard let characteristic = findCharacteristic() else { return }
        peripheral.writeValue(data, for: characteristic,
                             type: .withResponse)
    }

    // Tasdiqlashsiz yozish (withoutResponse)
    // Maksimal o'tkazish, yetkazib berish kafolatisiz
    func writeWithoutResponse(data: Data) {
        guard let characteristic = findCharacteristic() else { return }
        peripheral.writeValue(data, for: characteristic,
                             type: .withoutResponse)
    }

    private func findCharacteristic() -> CBCharacteristic? {
        return peripheral.services?
            .flatMap { $0.characteristics ?? [] }
            .first(where: { $0.uuid == charUUID })
    }
}

withResponse yoki withoutResponse yozish turini tanlash ishonchlilik talablariga bog'liq. Buyruqlar uchun (chiroqni yoqish, qulfni ochish) withResponse dan foydalaning — yetkazib berish kafolati muhim. Oqimli ma'lumotlar uchun (yurak urishi, harorat) withoutResponse dan foydalaning — bitta paketning yo'qolishi ahamiyatsiz. BLE qurilmasi faqat bitta yozish turini qo'llab-quvvatlashi mumkin — characteristic.properties.contains(.write) va .writeWithoutResponse xususiyatini tekshiring.

setNotifyValue orqali BLE bildirishnomalariga obuna bo'lish

Bildirishnomalar (notifications) — periferik qurilma xarakteristika qiymatini markaziy qurilmaga asinxron yuboradigan BLE mexanizmi, markaziy tomondan doimiy polling talab qilinmaydi. CBPeripheral setNotifyValue:forCharacteristic: metodi orqali obunani faollashtiradi. Obuna faollashtirilgandan so'ng, iOS avtomatik ravishda periferiyada CCCD (Client Characteristic Configuration Descriptor) ni yozadi va qurilma har bir qiymat o'zgarishida yangilanishlarni yuborishni boshlaydi.

Indikatsiyalardan (indicate) farqli o'laroq, bildirishnomalar markaziy tomondan tasdiqlashni talab qilmaydi — paket yuboriladi va unutiladi. Bu maksimal o'tkazish qobiliyatini beradi, ammo paket yo'qotilishi mumkin. Indikatsiyalar protokol darajasida (L2CAP) tasdiqlashni talab qiladi — ishonchliroq, lekin sekinroq. CBCharacteristic properties xususiyati orqali qaysi rejimni qo'llab-quvvatlashini aniq ko'rsatadi: .notify, .indicate yoki ikkalasi.

CBPeripheral uzilganda (disconnect, zonadan chiqishda) barcha faol obunalar avtomatik ravishda tiklanadi. Qayta ulanganda har bir xarakteristika uchun yana setNotifyValue:true chaqirilishi kerak. iOS ilova foreground-dan chiqqanda ham obunalarni yo'qotadi (background mode yoqilmagan bo'lsa) — fon ishi uchun Info.plist da „Uses Bluetooth LE accessories“ capability si yoqilgan bo'lishi kerak.

swift
// CBPeripheral bildirishnoma obunasini boshqarish
class NotificationManager: NSObject {

    private var peripheral: CBPeripheral?
    private var subscribedCharacteristics: Set<CBUUID> = []

    // Barcha .notify xarakteristikalar uchun bildirishnomalarga obuna bo'lish
    func subscribeToAllNotifications(peripheral: CBPeripheral) {
        self.peripheral = peripheral

        guard let services = peripheral.services else { return }

        for service in services {
            guard let characteristics = service.characteristics else { continue }

            for characteristic in characteristics {
                if characteristic.properties.contains(.notify)
                    || characteristic.properties.contains(.indicate) {
                    peripheral.setNotifyValue(true, for: characteristic)
                    subscribedCharacteristics.insert(characteristic.uuid)
                }
            }
        }
    }

    // Barcha bildirishnomalardan obunani bekor qilish
    func unsubscribeFromAll() {
        guard let peripheral = peripheral else { return }
        guard let services = peripheral.services else { return }

        for service in services {
            guard let characteristics = service.characteristics else { continue }

            for characteristic in characteristics {
                if subscribedCharacteristics.contains(characteristic.uuid) {
                    peripheral.setNotifyValue(false, for: characteristic)
                }
            }
        }
        subscribedCharacteristics.removeAll()
    }

    // Bildirishnoma handleri
    func peripheral(_ peripheral: CBPeripheral,
                     didUpdateNotificationStateFor characteristic: CBCharacteristic,
                     error: Error?) {
        if characteristic.isNotifying {
            print("Subscription active: \(characteristic.uuid)")
        } else {
            print("Subscription inactive: \(characteristic.uuid)")
        }
    }
}

NotificationManager obuna menejeri CBPeripheral bildirishnomalari bilan to'g'ri ishlashni namoyish etadi. subscribeToAllNotifications barcha servislar va xarakteristikalarni aylanib chiqadi, .notify va .indicate ni faollashtiradi. subscribedCharacteristics to'g'ri obunani bekor qilish uchun faol obunalarni kuzatadi. didUpdateNotificationStateForCharacteristic characteristic.isNotifying xususiyati orqali obuna holatining muvaffaqiyatli o'zgarishini tasdiqlaydi.

Swift-da CBPeripheral bilan ishlashning to'liq namunasi

CBPeripheral bilan to'liq ish sikli o'z ichiga oladi: CBCentralManager dan obyektni olish, ulanish, discovery, o'qish/yozish, bildirishnomalarga obuna bo'lish va uzish. Quyidagi misolda Swift-da zamonaviy async/await API (iOS 15+) yordamida BLE-periferiyaning to'liq hayot aylanishini boshqaradigan BLEConnection sinfi amalga oshirilgan.

swift
import CoreBluetooth

// async/await bilan to'liq CBPeripheral boshqarish namunasi
class BLEConnection: NSObject {

    private let centralManager: CBCentralManager
    private var peripheral: CBPeripheral?
    private var continuation: CheckedContinuation<Void, Error>?

    override init() {
        centralManager = CBCentralManager(delegate: nil, queue: .main)
        super.init()
        centralManager.delegate = self
    }

    // 1. Periferik qurilmaga ulanish
    func connect(to peripheral: CBPeripheral) async throws {
        self.peripheral = peripheral
        peripheral.delegate = self
        centralManager.connect(peripheral, options: nil)

        try await withCheckedThrowingContinuation { continuation in
            self.continuation = continuation
        }
    }

    // 2. Discovery  
    func discoverServices() async throws {
        guard let peripheral = peripheral else {
            throw BLEError.notConnected
        }
        peripheral.discoverServices(nil)
        try await withCheckedThrowingContinuation { continuation in
            self.continuation = continuation
        }
    }
}

// 3. CBCentralManager
extension BLEConnection: CBCentralManagerDelegate {
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        // Bluetooth qurilma holatini boshqarish
    }

    func centralManager(_ central: CBCentralManager,
                        didConnect peripheral: CBPeripheral) {
        continuation?.resume()
        continuation = nil
    }

    func centralManager(_ central: CBCentralManager,
                        didFailToConnect peripheral: CBPeripheral,
                        error: Error?) {
        continuation?.resume(throwing: error ?? BLEError.connectionFailed)
        continuation = nil
    }
}

enum BLEError: Error {
    case notConnected
    case connectionFailed
    case serviceNotFound
    case characteristicNotFound
}

BLEConnection sinfi CheckedContinuation orqali Swift Concurrency (async/await) dan foydalanadi — Core Bluetooth delegat API-lari bilan ishlash uchun zamonaviy namuna. connect(to:) didConnectPeripheral orqali ulanish tasdig'ini kutadi, discoverServices() — didDiscoverServices orqali. Bu yondashuv ichma-ich delegatlardan xalos qiladi va BLE kodini chiziqli va o'qiladigan qiladi. BLEError orqali xato boshqaruvi BLE ulanishining barcha tipik muvaffaqiyatsizlik stsenariylarini qamrab oladi.

Tez-tez beriladigan savollar

Skan qilmasdan CBPeripheral ni qanday olish mumkin?

CBPeripheral avval ulangan qurilma uchun CBCentralManager da retrievePeripheralsWithIdentifiers: orqali olinishi mumkin. Oldin saqlangan qurilmalarning UUID (NSUUID) massivini uzating — framework tizim BLE-bonding bazasidagi qurilmalar uchun CBPeripheral massivini qaytaradi. Bu faqat iPhone avval bog'langan qurilmalar uchun ishlaydi. Yangi qurilma uchun skan qilish majburiydir.

Nima uchun CBPeripheral servislarni topmaydi?

Asosiy sabablar: qurilma zonadan tashqarida (RSSI chegaradan past), BLE radiosi o'chirilgan (CBCentralManager.state != .poweredOn), CBPeripheralDelegate delegati o'rnatilmagan (peripheral.delegate = self) yoki discoverServices ulanishdan oldin chaqirilgan. centralManager.state holatini tekshiring, delegat connect chaqiruvidan oldin o'rnatilganligiga ishonch hosil qiling va 5–10 soniya taym-aut bilan retry dan foydalaning.

writeValue javob bermasa nima qilish kerak?

Sabab — faqat .writeWithoutResponse ni qo'llab-quvvatlovchi xarakteristikada .withResponse dan foydalanish yoki aksincha. characteristic.properties ni chaqiruvdan oldin tekshiring. MTU muammosi ham bo'lishi mumkin: agar ma'lumot > 20 bayt (BLE 4.0 MTU) bo'lsa, negotiateMTU yoki fragmentatsiya orqali MTU kelishuvi talab qilinadi. Maksimal paket hajmini aniqlash uchun peripheral.maximumWriteValueLength(for: .withResponse) dan foydalaning.

CBPeripheral ni zonadagidan mavjud bo'lmagandan qanday farqlash mumkin?

Zonadan tashqaridagi CBPeripheral darhol uzilmaydi — iOS uni taym-aut orqali (odatda 20–30 soniya) .disconnected holatiga o'tkazadi. Kuzatish uchun CBPeripheral da readRSSI dan foydalaning — mavjud bo'lmaganda CBError.connectionTimeout kodi bilan xato qaytaradi. Shuningdek, ulanish uzilishini o'z vaqtida aniqlash uchun centralManager:didDisconnectPeripheral:error: ni kuzating.

Bitta CBPeripheral ni bir nechta threadlardan ishlatish mumkinmi?

Core Bluetooth thread-xavfsiz emas — barcha CBPeripheral chaqiruvlari bitta navbatdan bajarilishi kerak (odatda main queue yoki CBCentralManager ishga tushirilganda ko'rsatilgan ketma-ket serial queue). Turli threadlardan bir vaqtning o'zida chaqiruvlar race condition va ilovaning ishdan chiqishiga olib keladi. Barcha BLE operatsiyalari uchun DispatchQueue(label: „com.app.ble“) va UI yangilash uchun DispatchQueue.main.async dan foydalaning.

Xulosa

  • CBPeripheral — CBCentralManager tomonidan qaytariladigan, iOS-da uzoqdagi BLE qurilmasi bilan ishlash uchun Core Bluetooth sinfi
  • GATT iyerarxiyasi servislardan (CBService), xarakteristikalardan (CBCharacteristic) va deskriptorlardan (CBDescriptor) 16-bit yoki 128-bit UUID bilan iborat
  • Discovery ketma-ket bajariladi: discoverServices: → discoverCharacteristics:forService: delegat orqali qayta ishlanadi
  • O'qish — readValueForCharacteristic:, yozish — writeValue:forCharacteristic:type: (.withResponse yoki .withoutResponse)
  • Bildirishnomalar — setNotifyValue:forCharacteristic: periferiyadan markazga asinxron ma'lumot yuborishni faollashtiradi
  • MTU BLE 4.0 paketni 23 bayt bilan cheklaydi, BLE 5.0+ — 251 baytgacha, MTU dan katta ma'lumotlar fragmentatsiyani talab qiladi
  • Async/await Swift CheckedContinuation orqali ichma-ich delegatlarni chiziqli chaqiruvlar bilan almashtirib, BLE kodini soddalashtiradi

Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz

IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.

Loyihani muhokama qilish

Shuningdek o'qing