Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't use TextAlignmentConstraint within Interface Builder #355

Open
mattcomi opened this issue Jan 24, 2019 · 4 comments
Open

Can't use TextAlignmentConstraint within Interface Builder #355

mattcomi opened this issue Jan 24, 2019 · 4 comments

Comments

@mattcomi
Copy link

Issue

I'm unable to use the TextAlignmentConstraint within Interface Builder.

Changing the custom constraint class to TextAlignmentConstraint has no effect and the attribute extra attributes do not appear in the attributes inspector. At runtime, this appears in the console:

Unknown class TextAlignmentConstraint in Interface Builder file.

This is a Swift project and I am trying to include the constraint within a UITableViewCell xib.

My Environment

I am using BonMot 5.3 via Carthage.

Things I've Tried

I can create the constraint in code no problem.

If I specify BONTextAlignmentConstraint for the custom class name in Interface Builder, it works but the extra attributes don't appear and it crashes at runtime on line 188 of TextAlignmentConstraint.swift:

let distanceFromTop1 = distanceFromTop(of: firstItem!, with: firstItemAttribute)

With:

Thread 1: Fatal error: Attempt to reason about unspecified constraint attribute

My suspicion is that Interface Builder can't find constraints within imported frameworks? If I create a custom constraint within my own project, it is able to find that. I tried this:

class MyTextAlignmentConstraint: TextAlignmentConstraint {}

But TextAlignmentConstraint is not open.

@ZevEisenberg
Copy link
Collaborator

Thanks for reporting this. On first reading, I believe this should be working. I’ll dig into it soon and get back to you. I don’t use Interface builder, so I wouldn’t be surprised if this had regressed. If I can fix it, I’ll add tests 😉

@ZevEisenberg
Copy link
Collaborator

Hey Matt,

Thanks again for your detailed bug report! I was able to reproduce your issue. I don't yet know what is causing it, but I have a little more info and two workaround for you.

Workaround 1

  1. You (apparently) have to use the Objective-C name of the class, which is BONTextAlignmentConstraint.
  2. You don't have to specify a module in Interface Builder.
  3. I havne't been able to get the @IBInspectable properties to work, but it does work if you pass the values manually in user-defined runtime attributes. You need to add entries for string properties called firstAlignment and secondAlignment, and you can pass any of these as values: top, cap height, x-height, first baseline, last baseline, bottom.

Workaround 2

Use CocoaPods. Unpopular opinion, perhaps, but I tested it and I was able to use the constraint as intended without any issues.

Unanswered Questions

I created a framework target inside my example project, and added a Swift file to it that looked like this:

import UIKit

@objc(PREFIXEDMyConstraint)
public class MyConstraint: NSLayoutConstraint {

    @IBInspectable var coolBeans: String?

    public override func awakeFromNib() {
        super.awakeFromNib()
        print("coolBeans:", String(describing: coolBeans))
    }
}

With that in place, I was able to refer to the class in Interface Builder as PREFIXEDMyConstraint, and set the inspectable properties without having to use user-defined runtime attributes. I don't know what the difference is with the Carthage-built framework, nor why it works in CocoaPods.

It looks like, at the very least, we should update the docs to make this more clear, but I'd love to find and fix the underlying issue.

@ZevEisenberg
Copy link
Collaborator

Here's a project that reproduces the issue. If you convert it over to using CocoaPods, you can use the constraint in IB without issue.

BonTest.zip

@jdhealy
Copy link
Contributor

jdhealy commented Feb 16, 2019

Yeah, it’s an Xcode limitation: anything pre-compiled (by Carthage or otherwise) doesn’t get the extra attributes in the attributes inspector.

You can remove the Carthage-compiled framework, use a workspace, and add and integrate (to that workspace) BonMot.xcodeproj. That should be all that’s necessary, but (with Xcode 10.1 and Zev’s BonTest.zip) Interface Builder can’t find the class for some reason — messing about, I kept seeing the error Unknown class __TtC6BonMot23TextAlignmentConstraint in Interface Builder file. There’s a couple workarounds, made a screencast showing one of them in effect:

https://archive.org/download/BONTextAlignmentConstraintScreencast/BONTextAlignmentConstraint%20Screencast.mp4

There’s another workaround involving editing BonMot source code, but honestly not really worth it…

That method — modifying class TextAlignmentConstraint: @objc(BONTextAlignmentConstraint)@objc // crossing fingers because we're no longer prefixing and clashes could result.

  • With this a symbol _OBJC_CLASS_$_BONTextAlignmentConstraint disappears and is replaced by _OBJC_CLASS_$__TtC6BonMot23TextAlignmentConstraint — see nm -gU BonMot.framework/BonMot | grep 'TextAlignmentConstraint'

Honestly, not sure either this or the method from the video are worth the hassle. Just using the user-defined runtime attributes is ergonomic enough.


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants