Home > database >  not key value coding-compliant in Swift class that extends ObjC subclass with @IBOutletCollection
not key value coding-compliant in Swift class that extends ObjC subclass with @IBOutletCollection

Time:11-15

I have a large app with LOTS of ObjC classes that we've written over the years. I'm trying to migrate over to Swift a bit at a time because I can't risk a mass shift that could break too many things.

This is my class hierarchy for my current problem:

OverFreeAnimalLimitViewController.swift (was originally ObjC) ->
FixBillingIssueViewController.swift (was originally ObjC) ->
BaseViewController.m ->
UIViewController

BaseViewController.m has:

@property(nullable, strong, nonatomic) IBOutletCollection(UIButton) NSArray<UIButton*> *appstring_buttons;

In the storyboard, I attach all of the buttons to that collection so that I can style them all programmatically instead of having to do that same configuration in the storyboard over and over again.

The underlying xml code in the storyboard looks like this:

<connections>
    <outletCollection property="appstring_buttons" destination="Kwf-Mv-Gis" id="ZzW-k6-Ydm"/>
    <outletCollection property="appstring_buttons" destination="f7s-5H-81g" id="xRb-XN-pNs"/>
</connections>

When OverFreeAnimalLimitViewController and FixBillingIssueViewController were written in objc, this worked properly.

I've converted them to swift and now the app crashes when processing the storyboard. When I run the app and the storyboard tries to attach all of the outlets and outletcollections, I get:

'NSUnknownKeyException', reason: '[<UIViewController 0x12b662370> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key appstring_buttons.'

I noticed the error message says UIViewController instead of OverFreeAnimalLimitViewController, so I checked the storyboard and the storyboard correctly lists the custom class as OverFreeAnimalLimitViewController for this view controller.

I've seen that swift only has @IBOutlet and doesn't explicitly have @IBOutletCollection because when you want to use a collection, you simply use an array type with the @IBOutlet annotation. But does that mean it'll hard-crash if it tries to use an underlying @IBOutletCollection?

In OverFreeAnimalLimitViewController.swift if I try to write code to reference self.appstring_buttons, Xcode will offer me this autocomplete:

enter image description here

Is there a way to fix this or is not possible to use a Swift class that extends from an ObjC class with @IBOutletCollections?

CodePudding user response:

Ok, I figured it out. It had to do with the internals of the Storyboard and not with the IBOutletCollection definitions.

I created a brand new project in Xcode to test this problem out and the outlet collections worked as intended, so I knew it wasn't a bug and there should be a proper solution for my real project.

One thing that had kept bugging me was that the error message said [<UIViewController 0x12b662370> setValue:forUndefinedKey:] with UIViewController instead of OverFreeAnimalLimitViewController. When I saw that problem at the very start of the issue, I immediately checked the storyboard to make sure the custom class had been set, because it looked like it was just loaded a bare UIViewController instead of my subclass. But I checked and it was set in the storyboard, so I dismissed that as the problem.

What Fixed It

I went into the storyboard and cleared out the Custom Class setting, so that it was just back to a standard UIViewController. Then I set OverFreeAnimalLimitViewController as the Custom Class again. Then it worked.

What it looks like is that when Xcode was setting the custom class, it looked for the referenced class and when it saw that it was a swift class, it added some extra attributes to the storyboard, i.e. the customModule and customModuleProvider which is what would allow it to load the proper class.

<viewController customClass="OverFreeAnimalLimitViewController" title="subscribe_to_sync" id="CMN-i2-ISu" sceneMemberID="viewController">
<viewController customClass="OverFreeAnimalLimitViewController" customModule="HerdBoss" customModuleProvider="target" title="subscribe_to_sync" id="CMN-i2-ISu" sceneMemberID="viewController">

After that, it was able to load the correct view controller subclass and then the outlets attached correctly.

  • Related