     // MARK: - Initialization
     
     public init(hostController: HostController,
-                options: GATTCentralOptions = GATTCentralOptions()) {
+                options: GATTCentralOptions = GATTCentralOptions(),
+                newConnection: NewConnection? = nil) {
         
         self.hostController = hostController
         self.options = options
+        self.newConnection = newConnection
     }
     
     // MARK: - Methods
     
-    public func scan(filterDuplicates: Bool = true,
-                     foundDevice: @escaping (ScanData<Peripheral, Advertisement>) -> ()) throws {
+    public func scan(filterDuplicates: Bool,
+                     _ foundDevice: @escaping (Result<ScanData<Peripheral, Advertisement>, Error>) -> ()) {
         
         precondition(isScanning == false, "Already scanning")
         
-        self.log?("Scanning...")
-        
-        self.isScanning = true
-        
-        do {
+        queue.async { [weak self] in
+            guard let self = self else { return }
+            self.log?("Scanning...")
+            self.isScanning = true
+            do {
+                try hostController.lowEnergyScan(filterDuplicates: filterDuplicates, parameters: options.scanParameters, shouldContinue: { [unowned self] in self.isScanning }) { [unowned self] (report) in
+                    
+                    let peripheral = Peripheral(identifier: report.address)
+                    let isConnectable = report.event.isConnectable
+                    let scanData = ScanData(
+                        peripheral: peripheral,
+                        date: Date(),
+                        rssi: Double(report.rssi.rawValue),
+                        advertisementData: report.responseData,
+                        isConnectable: isConnectable
+                    )
+                    self.scanData[peripheral] = (scanData, report)
+                    foundDevice(.success(scanData))
+                }
+            } catch {
+                self.isScanning = false
+                self.log?("Unable to scan: \(error)")
+            }
             
-            try hostController.lowEnergyScan(filterDuplicates: filterDuplicates, parameters: options.scanParameters, shouldContinue: { [unowned self] in self.isScanning }) { [unowned self] (report) in
-                
-                let peripheral = Peripheral(identifier: report.address)
-                
-                let isConnectable = report.event.isConnectable
-                
-                let scanData = ScanData(peripheral: peripheral,
-                                        date: Date(),
-                                        rssi: Double(report.rssi.rawValue),
-                                        advertisementData: report.responseData,
-                                        isConnectable: isConnectable)
-                
-                self.scanData[peripheral] = (scanData, report)
-                
-                foundDevice(scanData)
-            }
-        } catch {
-            self.isScanning = false
-            throw error
-        }
-        
-        self.log?("Did discover \(self.scanData.count) peripherals")
-        assert(isScanning == false, "Invalid scanning state: \(isScanning)")
+            self.log?("Did discover \(self.scanData.count) peripherals")
+            assert(isScanning == false, "Invalid scanning state: \(isScanning)")
+        }
     }
     
     public func stopScan() {

        self.isScanning = false
    }
    
    public func connect(to peripheral: Peripheral, timeout: TimeInterval = .gattDefaultTimeout) throws {
        
        guard let (scanData, report) = scanData[peripheral]
            else { throw CentralError.unknownPeripheral }
        
        guard let newConnection = self.newConnection
            else { return }
        
        // log
        self.log?("[\(scanData.peripheral)]: Open connection (\(report.addressType))")
        
        // open socket
        let socket = try async(timeout: timeout) { try newConnection(scanData, report) }
        
        // configure connection object
        let callback = GATTClientConnectionCallback(
            log: self.log,
            didDisconnect: { [weak self] _ in
                self?.disconnect(peripheral: peripheral)
            }
        )
        
        // keep connection open and store for future use
        let connection = GATTClientConnection(peripheral: peripheral,
                                              socket: socket,
                                              maximumTransmissionUnit: options.maximumTransmissionUnit,
                                              callback: callback)
        
        // store connection
        self.connections[peripheral] = connection
    }
    
    public func disconnect(peripheral: Peripheral) {
        
        self.connections[peripheral] = nil
        
        // L2CAP socket may be retained by background thread
        sleep(1)
        
        didDisconnect?(peripheral)
    }
    
    public func disconnectAll() {
        
        let peripherals = self.didDisconnect != nil ? Array(self.connections.keys) : []
        
        self.connections.removeAll(keepingCapacity: true)
        
        sleep(1)
        
        if let didDisconnect = self.didDisconnect {
            peripherals.forEach { didDisconnect($0) }
        }
    }
    
    public func discoverServices(_ services: [BluetoothUUID] = [],
                                 for peripheral: Peripheral,
                                 timeout: TimeInterval = .gattDefaultTimeout) throws -> [Service<Peripheral, AttributeID>] {
        
        return try connection(for: peripheral)
            .discoverServices(services, for: peripheral, timeout: timeout)
    }
    
    public func discoverCharacteristics(_ characteristics: [BluetoothUUID] = [],

    
    public var didDisconnect: ((Peripheral) -> ())?
    
    @available(*, deprecated, message: "Set value in `.init()`")
    public var newConnection: NewConnection?
    
    private lazy var queue = DispatchQueue(label: "\(type(of: self)) Queue")
    
    private lazy var concurrentQueue = DispatchQueue(label: "\(type(of: self)) Async Queue", qos: .userInitiated, attributes: [.concurrent])
    
    internal private(set) var scanData: [Peripheral: (ScanData<Peripheral, Advertisement>, HCILEAdvertisingReport.Report)] = [:]
    
