CBPeripheral: nedir, yöntemleri ve iOS'ta BLE çevre birimlerini yönetme

Yazar: IT Sectr Yayınlanma: 2026-07-16 Okuma süresi: 10 dk

CBPeripheral, iOS'ta uzak bir BLE cihazını temsil eden Core Bluetooth framework sınıfıdır. Her CBPeripheral nesnesi, bağlı bir BLE cihazının UUID'sini, adını, RSSI'sini ve GATT hizmet hiyerarşisini kapsüller. Geliştirici, çevre birimiyle yalnızca CBPeripheral aracılığıyla etkileşime girer: hizmet keşfi (discoverServices:), karakteristik okuma (readValueForCharacteristic:), veri yazma (writeValue:forCharacteristic:type:) ve bildirim aboneliği (setNotifyValue:forCharacteristic:). Apple Developer, 2026'ya göre CBPeripheral, bir cihaz keşfedildiğinde veya bağlandığında CBCentralManager tarafından döndürülen, tüm BLE çevre birimi işlemleri için merkezi nesnedir.

Önemli Noktalar

  • CBPeripheral, iOS'ta uzak bir BLE cihazıyla çalışmak için Core Bluetooth sınıfıdır
  • GATT Hiyerarşisi — Peripheral, hizmetler (CBService) içerir, hizmetler karakteristikler (CBCharacteristic) içerir, karakteristikler tanımlayıcılar (CBDescriptor) içerir
  • Keşif — Bir cihazın GATT yapısını almak için discoverServices: ve discoverCharacteristics:forService:
  • Okuma ve Yazma — readValueForCharacteristic: ve writeValue:forCharacteristic:type: yanıtlı (withResponse) veya yanıtsız (withoutResponse)
  • Bildirimler — setNotifyValue:forCharacteristic:, BLE cihazı karakteristik değişikliklerine aboneliği etkinleştirir

CBPeripheral Nedir: Özü ve Amacı

CBPeripheral, bir iOS uygulamasında uzak bir BLE cihazını temsil eden bir nesnedir. iPhone'un yerel Bluetooth adaptörünü yöneten CBCentralManager'ın aksine, CBPeripheral harici bir çevre birimi cihazını modeller: bir sensör, fitness takip cihazı, işaretçi veya tıbbi cihaz. Her CBPeripheral örneği, bağlantı oturumları arasında kalıcı olan benzersiz bir tanımlayıcı (UUID) içerir — Apple, UUID'yi sistem Bonding'i aracılığıyla belirli bir cihaza bağlar.

CBPeripheral doğrudan init aracılığıyla oluşturulmaz. Core Bluetooth framework'ü, CBPeripheral nesnesini iki senaryoda döndürür: bir cihaz scanForPeripheralsWithServices: aracılığıyla keşfedildiğinde (delege didDiscoverPeripheral) ve retrievePeripheralsWithIdentifiers: aracılığıyla önceden bilinen bir cihaza bağlanıldığında. Nesne alındıktan sonra, geliştirici CBCentralManager üzerinde connectPeripheral: çağrısını yapar ve ardından CBPeripheral GATT işlemleri için kullanılabilir hale gelir.

CBPeripheral Yaşam Döngüsü altı durum içerir: bağlantı kesik (başlangıç), bağlanıyor (connect çağrısından sonra), bağlı (didConnectPeripheral'den sonra), keşfediyor (discoverServices çağrısı sırasında), keşfedildi (hizmetler alındıktan sonra) ve bağlantı kesiyor (cancelPeripheralConnection'dan sonra). Her durum, CBPeripheralDelegate protokolü aracılığıyla izlenir — iOS'taki herhangi bir BLE uygulaması için olmazsa olmazdır.

CBPeripheral ve GATT Hiyerarşisi: Hizmetler, Karakteristikler, Tanımlayıcılar

CBPeripheral, üç seviyeden oluşan hiyerarşik bir GATT yapısı depolar. Kök seviye, bir CBService (hizmet) dizisidir, her hizmet bir CBCharacteristic (karakteristik) dizisi içerir, her karakteristik bir CBDescriptor (tanımlayıcı) dizisi içerir. Bu model, Bluetooth GATT spesifikasyonuna tamamen uygundur: bir hizmet, bir cihaz işlevidir (örneğin, “Kalp Atış Hızı Servisi”), bir karakteristik belirli bir değerdir (nabız 72 bpm), bir tanımlayıcı karakteristik meta verileridir (ölçüm birimleri, bildirim yapılandırması).

SeviyeCore Bluetooth SınıfıAçıklama
HizmetCBServiceİlgili karakteristiklerin mantıksal grubu, UUID (16-bit, 32-bit veya 128-bit) ile tanımlanır
KarakteristikCBCharacteristicBelirli veri değeri, okuma, yazma ve bildirimleri destekler
TanımlayıcıCBDescriptorKarakteristik meta verileri: istemci yapılandırması CCCD, kullanıcı açıklaması, sunum formatı

Standart BLE hizmetleri Bluetooth SIG tarafından kaydedilmiştir: Heart Rate Service (UUID 180D), Battery Service (180F), Device Information (180A), Blood Pressure (1810). Özel hizmetler için 128-bit UUID'ler kullanılır (örneğin, E20A39F4-73F5-4BC4-A12F-17D1AD07A961). iOS, standart UUID'leri otomatik olarak tanır ve insan tarafından okunabilir adlar görüntüler; özel UUID'ler onaltılık formatta görünür.

Bağlantıdan sonra, CBPeripheral hiyerarşisi boştur — hizmetler ve karakteristikler yüklenmemiştir. Geliştirici, hizmetleri almak için discoverServices: çağrısını ve ardından her hizmet için discoverCharacteristics:forService: çağrısını yapmalıdır. Hizmet, dahil edilen hizmetler içeriyorsa, ayrıca discoverIncludedServices:forService: çağrılır. Hiyerarşi keşfi tamamlandıktan sonra CBPeripheral doldurulur ve okuma ve yazma için kullanılabilir hale gelir.

Hizmet ve Karakteristik Keşfi: Yöntemler ve Delegeler

Keşif CBPeripheral'ın GATT yapısının keşfi, herhangi bir okuma veya yazma işleminden önce zorunlu bir adımdır. discoverServices: yöntemi, tüm cihaz hizmetlerinin asenkron bir aramasını başlatır. Nil iletilirse, tüm hizmetler keşfedilir; bir CBUUID dizisi iletilirse — yalnızca belirtilen UUID'lere sahip hizmetler (zaman optimizasyonu). Sonuç, delege peripheral:didDiscoverServices:'a gelir — CBPeripheral nesnesi, services özelliğini bir CBService dizisiyle doldurur.

Hizmetler alındıktan sonra, her CBService için discoverCharacteristics:forService: çağrılmalıdır. Benzer şekilde, nil — tüm karakteristikler, CBUUID dizisi — yalnızca belirtilenler. Sonuç: peripheral:didDiscoverCharacteristicsForService:error:. Bu aşamada, CBCharacteristic, izin verilen işlemleri tanımlayan özellikler (properties: .read, .write, .notify, .indicate) alır.

swift
import CoreBluetooth

extension BLEViewController: CBPeripheralDelegate {

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

        for service in services {
            // Request characteristics for each service
            peripheral.discoverCharacteristics(nil, for: service)
        }
    }

    // 2. Characteristic discovery
    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. Read value
    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)")
    }
}

Örnekte, CBPeripheralDelegate üç zorunlu keşif yöntemini uygular. didDiscoverServices, bulunan tüm hizmetler üzerinde yinelenir ve karakteristikleri ister. didDiscoverCharacteristicsForService, her karakteristiğin özelliklerini kontrol eder: .read için readValue'yu, .notify için setNotifyValue(true)'u çağırır. didUpdateValueForCharacteristic yöntemi, Data formatında gerçek değeri alır.

Karakteristik Okuma ve Yazma: withResponse ve withoutResponse

Değer Okuma CBCharacteristic değerinin okunması, readValueForCharacteristic: yöntemi kullanılarak gerçekleştirilir. Sonuç, asenkron olarak peripheral:didUpdateValueForCharacteristic:error:'a gelir. Önemli: cihazda önbelleğe alınmış bir değer olabilir (karakteristik keşfinden hemen sonra characteristic.value kullanılabilir), ancak güncel veriyi almak için readValue çağrısı zorunludur. iOS, enerji verimliliği için değerleri önbelleğe alabilir — readValue önbelleği yeniler.

Değer Yazma, writeValue:forCharacteristic:type: yöntemi kullanılarak gerçekleştirilir. type parametresi yazma türünü belirler: .withResponse (CBCharacteristicWriteWithResponse) — cihaz, didWriteValueForCharacteristic aracılığıyla yazmayı onaylar; .withoutResponse (CBCharacteristicWriteWithoutResponse) — onaysız yazma, maksimum hız ancak teslimat garantisi yoktur. BLE spesifikasyonu, MTU'yu (Maksimum İletim Birimi) sınırlar: BLE 4.0 için 23 bayta kadar, BLE 5.0+ için 251 bayta kadar. MTU'dan büyük veriler için uygulama düzeyinde parçalama gereklidir.

swift
// CBPeripheral characteristic read and write
class BLEService {

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

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

    // Read with response
    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)
    }

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

    // Write without response (withoutResponse)
    // Max throughput, no delivery guarantee
    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 })
    }
}

Yazma türü withResponse veya withoutResponse seçimi, güvenilirlik gereksinimlerine bağlıdır. Komutlar için (ışığı açmak, kilidi açmak) withResponse kullanın — teslimat garantisi kritiktir. Akış verileri için (nabız, sıcaklık) withoutResponse kullanın — bir paketin kaybı önemsizdir. Bir BLE cihazı yalnızca bir yazma türünü destekleyebilir — characteristic.properties.contains(.write) ve .writeWithoutResponse özelliklerini kontrol edin.

setNotifyValue ile BLE Bildirimlerine Abone Olma

Bildirimler, çevre birimi cihazının karakteristik değerlerini merkez cihaza asenkron olarak gönderdiği bir BLE mekanizmasıdır ve merkez tarafından sürekli yoklama yapılmaz. CBPeripheral, setNotifyValue:forCharacteristic: yöntemi aracılığıyla aboneliği etkinleştirir. Abonelik etkinleştirildikten sonra, iOS otomatik olarak çevre birimindeki CCCD'ye (İstemci Karakteristik Yapılandırma Tanımlayıcısı) yazar ve cihaz, değer her değiştiğinde güncellemeler göndermeye başlar.

İndikasyonların aksine, bildirimler merkez cihazdan onay gerektirmez — paket gönderilir ve unutulur. Bu, maksimum verim sağlar ancak paket kaybı mümkündür. İndikasyonlar, protokol düzeyinde (L2CAP) onay gerektirir — daha güvenilir ancak daha yavaştır. CBCharacteristic'in properties özelliği, hangi modun desteklendiğini tam olarak belirtir: .notify, .indicate veya her ikisi.

CBPeripheral bağlantısı kesildiğinde (bağlantı kesme, menzil dışı), tüm aktif abonelikler otomatik olarak sıfırlanır. Yeniden bağlanıldığında, her karakteristik için tekrar setNotifyValue:true çağrılmalıdır. iOS, uygulama ön plandan çıktığında da abonelikleri kaybeder (arka plan modu etkin değilse) — arka plan çalışması için Info.plist'te “Uses Bluetooth LE accessories” yeteneği etkinleştirilmelidir.

swift
// CBPeripheral notification subscription management
class NotificationManager: NSObject {

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

    // Subscribe to notifications for all .notify characteristics
    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)
                }
            }
        }
    }

    // Unsubscribe from all notifications
    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()
    }

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

NotificationManager, CBPeripheral bildirimlerinin doğru şekilde işlenmesini gösterir. subscribeToAllNotifications, tüm hizmetler ve karakteristikler üzerinde yinelenir, .notify ve .indicate'i etkinleştirir. subscribedCharacteristics, doğru abonelik iptali için aktif abonelikleri izler. didUpdateNotificationStateForCharacteristic, characteristic.isNotifying özelliği aracılığıyla başarılı abonelik durumu değişikliğini onaylar.

Swift'te Tam CBPeripheral Örneği

Tam İş Akışı CBPeripheral ile: CBCentralManager'dan nesne alma, bağlantı, keşif, okuma/yazma, bildirim aboneliği ve bağlantı kesme. Aşağıdaki örnek, modern async/await API'sini (iOS 15+) kullanarak Swift'te tam bir BLE çevre birimi yaşam döngüsünü yöneten BLEConnection sınıfını uygular.

swift
import CoreBluetooth

// Full CBPeripheral management example with async/await
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. Connect to peripheral
    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) {
        // Handle Bluetooth device state
    }

    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 sınıfı, CheckedContinuation aracılığıyla Swift Concurrency (async/await) kullanır — Core Bluetooth'un delege tabanlı API'si ile çalışmak için modern bir desen. connect(to:), didConnectPeripheral aracılığıyla bağlantı onayını bekler, discoverServices() — didDiscoverServices aracılığıyla. Bu yaklaşım, iç içe geçmiş delegeleri ortadan kaldırır ve BLE kodunu doğrusal ve okunabilir hale getirir. BLEError aracılığıyla hata işleme, tüm tipik BLE bağlantı hatası senaryolarını kapsar.

Sıkça Sorulan Sorular

Tarama yapmadan CBPeripheral nasıl alınır?

CBPeripheral, daha önce bağlanmış bir cihaz için CBCentralManager üzerinde retrievePeripheralsWithIdentifiers: aracılığıyla alınabilir. Daha önce kaydedilmiş cihazların UUID (NSUUID) dizisini iletin — framework, sistem BLE bonding veritabanındaki cihazlar için bir CBPeripheral dizisi döndürür. Bu yalnızca iPhone'un daha önce eşleştirdiği cihazlarla çalışır. Yeni bir cihaz için tarama zorunludur.

CBPeripheral neden hizmetleri keşfetmiyor?

Yaygın nedenler: cihaz menzil dışında (RSSI eşik değerinin altında), BLE radyosu kapalı (CBCentralManager.state != .poweredOn), CBPeripheralDelegate ayarlanmamış (peripheral.delegate = self) veya discoverServices bağlantıdan önce çağrılmış. centralManager.state'i kontrol edin, connect çağrısından önce delegenin ayarlandığından emin olun ve 5–10 saniye zaman aşımı ile yeniden deneme kullanın.

writeValue yanıt vermezse ne yapılmalı?

Nedeni, yalnızca .writeWithoutResponse destekleyen bir karakteristikte .withResponse kullanmaktır veya tam tersi. Çağrıdan önce characteristic.properties'i kontrol edin. Diğer bir olası sorun MTU'dur: veri 20 baytı (BLE 4.0 MTU) aşarsa, negotiateMTU veya parçalama yoluyla MTU müzakeresi gereklidir. Maksimum paket boyutunu belirlemek için peripheral.maximumWriteValueLength(for: .withResponse) kullanın.

Menzildeki CBPeripheral ile kullanılamayan nasıl ayırt edilir?

Menzil dışındaki CBPeripheral hemen bağlantıyı kesmez — iOS, bir zaman aşımından (genellikle 20–30 saniye) sonra onu .disconnected durumuna geçirir. İzleme için CBPeripheral üzerinde readRSSI kullanın — kullanılamıyorsa, CBError.connectionTimeout koduyla bir hata döndürür. Bağlantı kaybını zamanında tespit etmek için centralManager:didDisconnectPeripheral:error: öğesini de izleyin.

Tek bir CBPeripheral birden çok iş parçacığından kullanılabilir mi?

Core Bluetooth iş parçacığı güvenli değildir — tüm CBPeripheral çağrıları aynı kuyruktan (genellikle ana kuyruk veya CBCentralManager başlatılırken belirtilen seri kuyruk) yapılmalıdır. Farklı iş parçacıklarından eşzamanlı çağrılar, yarış koşullarına ve uygulama çökmelerine neden olur. Tüm BLE işlemleri için DispatchQueue(label: “com.app.ble”) ve UI güncellemeleri için DispatchQueue.main.async kullanın.

Özet

  • CBPeripheral, iOS'ta uzak bir BLE cihazıyla çalışmak için Core Bluetooth sınıfıdır, CBCentralManager tarafından döndürülür
  • GATT hiyerarşisi, 16-bit veya 128-bit UUID'lere sahip hizmetler (CBService), karakteristikler (CBCharacteristic) ve tanımlayıcılardan (CBDescriptor) oluşur
  • Keşif sırayla gerçekleştirilir: discoverServices: → discoverCharacteristics:forService: delege işleme ile
  • Okuma — readValueForCharacteristic:, yazma — writeValue:forCharacteristic:type: (.withResponse veya .withoutResponse)
  • Bildirimler — setNotifyValue:forCharacteristic:, çevre biriminden merkeze asenkron veri iletimini etkinleştirir
  • MTU, BLE 4.0 için paketleri 23 baytla sınırlar, BLE 5.0+ — 251 bayta kadar, MTU'yu aşan veriler parçalama gerektirir
  • Swift async/await, CheckedContinuation aracılığıyla BLE kodunu basitleştirir, iç içe delegeleri doğrusal çağrılarla değiştirir

Anahtar teslim bir mobil uygulama geliştireceğiz

IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.

Projeyi tartış

Ayrıca okuyun