Subclassing NSLayoutConstraint, bizarre behavior of constants
I don't think it's a good idea to subclass NSLayoutConstraint
. I don't think it was designed to be subclassed outside of Apple.
Anyway, the problem is that NSLayoutConstraint
conforms to the NSCoding
protocol, but doesn't declare that it conforms to NSCoding
in the header files. Because of this, Swift doesn't know that NSLayoutConstraint
can be initialized by -[NSLayoutConstraint initWithCoder:]
, so it doesn't generate an override of initWithCoder:
that initializes the instance variables you add in your subclass.
Here's how to fix it.
First, if your project doesn't have a bridging header, add one. The easiest way to add one is to create a new Objective-C class in your project, accept Xcode's offer to create the bridging header, then delete the .h
and .m
files it created for the class (but keep the bridging header).
Then, in the bridging header, declare that NSLayoutConstraint
conforms to NSCoding
:
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
@import UIKit;
@interface NSLayoutConstraint (MyProject) <NSCoding>
@end
Finally, in your Constrainty
class, override init(coder:)
like this:
required init(coder decoder: NSCoder) {
super.init(coder: decoder)!
}
Et voila:
HERE WE GO 77.0 350.0
result is 246.4
My wild guess it's all because of a class named UIClassSwapper
. It's a private class that handles all the UI objects initialization from the Interface Builder files. I would suggest to replace your let
constants with computed properties.
//...
var percentageWidht: CGFloat { // nothing up my sleeve
return 77.0
}
var limitWidth: CGFloat {
return 110.0
}
//...
UPD
Swift default property values(properties with values in their declaration) are being set before the initializer call. E.G. if you have a class MyClass
with a property let someVar: CGFloat = 12.0
and it's bridged to Objective-C, when you allocate memory for your object and do not call an initializer MyClass *obj = [MyClass alloc]
your variable will have a default value of 0.0 and will stay so unless you’ll call an initializer like [obj init]
. So my second wild guess is that because NSLayoutConstraint
class is written in Objective-C and it's initWithCoder:
initializer isn't declared in it's header(it's private), the ObjC-Swift bridging mechanism doesn't recognize it's call as an initializer call(it thinks it is just a simple instance method), so your Swift properties with default values aren't being initialized at all.