Debugging Errors: dyld: Symbol not found

,

I recently wanted to update my Steps Tracker App to allow purchasers of the Series 4 Apple Watch the ability to see the steps complication on the new Infograph watch faces that are only available on the new devices.

I managed to get the new complication styles working by reading the documents at developer.apple.com and tested them out using the simulator. After releasing a beta via Testflight it became apparent that on a Series 0 (i.e. the original Apple Watch) that can not run watchOS 5 the App was crashing.

I had forgotten to test it on watchOS 4.3. Doing so revealed an error dyld: Symbol not found: _OBJC_CLASS_$_CLKFullColorImageProvider.

I realised that CLKFullColorImageProvider class was only available in watchOS 5 and so wrapped all calls to this and the new info graph complications in an #available block like so.

if #available(watchOSApplicationExtension 5.0, *) {

let rectangular = CLKComplicationTemplateGraphicRectangularTextGauge()
let complicationImage = UIImage(named: "Complication/Graphic Large Rectangular")!
rectangular.headerImageProvider = CLKFullColorImageProvider(fullColorImage: complicationImage)
let gauge = CLKSimpleGaugeProvider(style: .fill, gaugeColors: [UIColor.cyan,UIColor.blue,UIColor.green], gaugeColorLocations: [0.0,0.5,0.66], fillFraction: 0.75)
rectangular.gaugeProvider = gauge
rectangular.headerTextProvider = CLKSimpleTextProvider(text: "7572 Steps", shortText: "7572")
rectangular.body1TextProvider = CLKSimpleTextProvider(text: "75% of your 10,000 target", shortText: "75%")
handler(rectangular)

}

My understanding was that if the OS version was not 5.0 or above the code inside would be skipped over. However I was still receiving the same error. I googled for an answer and some similar issues with dyld and other classes not being found suggested ‘weak linking the relevant framework‘. So I added the ClockKit framework to my watch extension’s Build Phases.

Unfortunately this still didn’t seem to get rid of the error for me. Finally after searching for some tutorials on supporting lower OS versions, I came across this article on Ray Wenderlich for Availability Attributes in Swift.

So I decided to move my code into a function and then call it inside my if #available block. I also used if #available(watchOS 5.0, *) { instead for good measure.

So my code for the InfoGraph Rectangular Text Gauge ended up looking like this.

case .graphicRectangular:
if #available(watchOS 5, *) {
let template = graphicRectuangularTemplate()
handler(template)
}

@available(watchOS 5.0, *)
func graphicRectuangularTemplate() -> CLKComplicationTemplate {
let rectangular = CLKComplicationTemplateGraphicRectangularTextGauge()
let complicationImage = UIImage(named: "Complication/Graphic Large Rectangular")!
rectangular.headerImageProvider = CLKFullColorImageProvider(fullColorImage: complicationImage)
let gauge = CLKSimpleGaugeProvider(style: .fill, gaugeColors: [UIColor.cyan,UIColor.blue,UIColor.green], gaugeColorLocations: [0.0,0.5,0.66], fillFraction: 0.75)
rectangular.gaugeProvider = gauge
rectangular.headerTextProvider = CLKSimpleTextProvider(text: "7572 Steps", shortText: "7572")
rectangular.body1TextProvider = CLKSimpleTextProvider(text: "75% of your 10,000 target", shortText: "75%")
return rectangular
}

Most of the stuff I read regarding linking of frameworks in build phases suggests it was not necessary since iOS4, but I found I needed to link ClockKit. Maybe this is still require in watchOS but not in iOS?

If you’ve had a similar issue, and found another way around it, please let me know in the comments or tweet me @drewwestcott

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.