Search code examples
iosobjective-cswiftcastingnsarray

I don't understand why an Objective-C delegate function works and a Swift delegate function crash. Can you explain to me?


I have a framework built in Objetive-C. That framework is to connect and interact with a Bluetooth device.

In the demo code, the Objetive-C delegate function looks like. The demo code was provided by the creator of the framework.

-(void)babyScaleManagerScanDevices:(NSArray<ELBabyScaleDeviceModel *> *)babyScaleDevices{
    NSLog(@"babyScaleManagerScanDevices = %@",babyScaleDevices);
    ELBabyScaleDeviceModel *model = babyScaleDevices.firstObject;
}

I've included the framework in my swift project and imported the headers. I'm trying to obtain the same result by doing:

func babyScaleManagerScanDevices(_ babyScaleDevices: [ELBabyScaleDeviceModel]?) {
    guard let device = babyScaleDevices?.first else {
      print("Error unwrapping first device")
      return
    }
    print("Device: \(String(describing: device))")
  }

I get the following exception:

Thread 1: Precondition failed: NSArray element failed to match the Swift Array Element type
Expected ELBabyScaleDeviceModel but found ELPeripheralModel

Precondition failed: NSArray element failed to match the Swift Array Element type
Expected ELBabyScaleDeviceModel but found ELPeripheralModel: file /BuildRoot/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-1100.2.274.2/swift/stdlib/public/core/ArrayBuffer.swift, line 354

Inspecting babyScaleDevices array show:

babyScaleDevices    [ELBabyScaleDeviceModel]?   1 value some
[0] ELPeripheralModel * 0x281cae100 0x0000000281cae100

This result is the same in the demo code in Objetive-C and my Swift project.

The class ELBabyScaleDeviceModel.h looks like:

#import "ELPeripheralModel.h"

NS_ASSUME_NONNULL_BEGIN

@interface ELBabyScaleDeviceModel : ELPeripheralModel

@end

NS_ASSUME_NONNULL_END

Can you explain me what is happening?


Solution

  • You have to specify Array to NSArray

    Add this line to your code

    let devices = babyScaleDevices as NSArray
    

    You can try this

    func babyScaleManagerScanDevices(_ babyScaleDevices: [ELBabyScaleDeviceModel]?) {
    let devices = babyScaleDevices as NSArray
    guard let device = devices.firstObject else {
        print("Error unwrapping first device")
        return
    }
    print("Device: \(String(describing: device))")
    

    }

    And after then check this -> Array vs NSArray