On whatever project you're currently working on, simply
On any screen drop in a UIView
Just add a width constraint (666 or whatever is fine),
Change the custom class of the constraint, to Constrainty
Run the app,
How can this possibly be?
Does it actually call for the value of the constant, "before the class is initialized," or some such?
How can it happen, and how to solve?
At first, I had the two variables as @IBInspectable
and I was surprised that didn't work at all. But then I changed them to ordinary let constants - and that doesn't work!
class Constrainty: NSLayoutConstraint {
let percentageWidth: CGFloat = 77 // nothing up my sleeve
let limitWidth: CGFloat = 350
override var constant: CGFloat {
get { return teste() }
set { super.constant = newValue }
}
func teste()->CGFloat {
print("\n\n HERE WE GO \(percentageWidth) \(limitWidth) \n\n")
if let sw = (firstItem as? UIView)?.superview?.bounds.width {
let w = sw * ( percentageWidth / 100.0 )
let r = w > limitWidth ? limitWidth : w
print("result is \(r) \n\n")
return r
}
return 50
}
}
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.