How to create EAAccessory instance?

I need to trigger accessory connected notification for testing purposes, for which I need to create an instance of EAAccessory class and send a fake accessory. How do I do that? I get this exception `EAAccessoryInitException`. *** Terminating app due to uncaught exception ‘EAAccessoryInitException’, reason: ‘-init not supported. EAAccessoryManager is responsible for creating all objects.’ Is there any other way to test this behavior?

Replies

That’s not going to work, alas. When dealing with complex system types like

EAAccessory
you can’t just conjure them out of thin air.

One way to deal with this is to create a custom protocol that encapsulates all the services that this part of your app needs and then:

  • Conform

    EAAccessory
    to that protocol for use within your app
  • Create a dummy type that conforms to that protocol for use within your tests

For example, imagine that your notification code maintains a mapping from the connection ID to the accessory. That might be declared like this:

var accessoriesByID: [Int:EAAccessory] = [:]

Instead, you can declare it like this:

protocol MyAccessory : AnyObject {
    var connectionID: Int { get }
}

var accessoriesByID: [Int:MyAccessory] = [:]

You can now conform

EAAccessory
to
MyAccessory
for use in your real app.
extension EAAccessory : MyAccessory {
}

You don’t need to write any code here because

EAAccessory
already satisfies the protocol requirements.

And for testing you can create a dummy accessory that conforms to the protocol:

class DummyAccessory : MyAccessory {
    var connectionID: Int = 0
}

Note that while this example is in Swift you can do a similar thing in Objective-C (and it may turn out to be easier because Objective-C is a little more flexible when it comes to protocol requirements).

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
  • I coded objective c version but I got -[DummyAccessory _protocolIDForProtocolString:]: unrecognized selector sent to instance error

Add a Comment

How can you then inject that into a property that must return only EAAccessory objects, such as EAAccesoryManager.shared().connectedAccessories ?

I would abstract my access to that property as well.

Alternatively, you could build a high-level abstraction layer that represents an accessory and then implement that twice, one on top of EA framework and against using dummy accessories for testing. You’ll have to test that abstraction layer with real accessories, but you can test the rest of your app against dummies.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I coded objective c version but I got -[DummyAccessory _protocolIDForProtocolString:]: unrecognized selector sent to instance error

It’s hard to say what’s going on here without looking at your code in more detail. I encourage you to start a new thread with those details. Feel free to reference this thread for context. Oh, and tag it with ExternalAccessory, Testing and Objective-C so that I see it.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"