I have this extension:
extension UIEdgeInsets {
init(top: CGFloat = 0, left: CGFloat = 0, bottom: CGFloat = 0, right: CGFloat = 0) {
self.init(top: top, left: left, bottom: bottom, right: right)
}
}
The purpose of the extension is to not have to pass parameters to the UIEdgeInsets initializer when they're not different from the default values. But when the custom initializer runs, an error is thrown:
Thread 1: EXC_BAD_ACCESS (code=2, address=0x16f997ff8)
Any idea why this code would cause a runtime error?
You are causing infinite recursion since you are calling the same init method from within itself.
And an extension really shouldn't try to override an existing init or other method simply by providing default parameters.
There is already an init(top:,left:,bottom:,right:). Providing another with the same signature is a bad idea.
But that aside, your primary issue is calling self.init from within the same init method.
To see the problem, add a print statement:
init(top: CGFloat = 0, left: CGFloat = 0, bottom: CGFloat = 0, right: CGFloat = 0) {
print("Uh-oh")
self.init(top: top, left: left, bottom: bottom, right: right)
}
As another example, create a class with an init that takes one parameter. Now add the same init again to the class but provide a default to the parameter. The code won't even compile. So trying to do the same through an extension is just going to lead to problems, even if you could solve the recursion problem.
Related
I wanted to update the UIEdgeInsets of all my view controllers on certain devices and I wanted to see if there's a way to do it globally as an extension, rather than creating a method and calling it in viewDidLoad for each of them. Is there a way to achieve this? I tried using awakeFromNib but this doesn't work.
extension UIViewController {
open override func awakeFromNib() {
self.additionalSafeAreaInsets = UIEdgeInsets(top: 100, left: 100, bottom: 100, right: 100)
}
}
I also tried calling self.viewLayoutMarginsDidChange() after changing the edge insets, with no results.
Any suggestions would be appreciated. Am I just overriding the wrong method or is this just not possible, or as easy as I'm thinking.
extension UIViewController {
open override func awakeAfter(using: NSCoder) -> Any? {
self.additionalSafeAreaInsets = UIEdgeInsets(top: 100, left: 100, bottom: 100, right: 100)
return super.awakeAfter(using: using)
}
}
I am using custom font for non-editable NSTextField, which I created in StoryBoard:
generalDisplay.font = NSFont(name: "DS-Digital Bold", size: 25.0)
Then I am adjusting frame height:
generalDisplay.frame.size.height = 28
The result is not centered vertically:
I've tried to turn off single line mode, but the result is even worse.
If I should subclass it, could you give me an example what methods I have to override?
You can subclass UITextField and override this method:
override func textRect(forBounds bounds: CGRect) -> CGRect {
return bounds.inset(by: UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 10))
}
Looking at the Apple documentation for NSTextfield maybe you could initialize your NSTextField with a NSAttributedString to be able to change the baseline
NSTextfield(labelWithAttributedString: NSAttributedString)
I am trying to implement a custom UISegmented Control into my program. Is there a way that I can use Auto Layout alongside CGRect (without having a ton of layout conflicts) or get rid of it altogether?
Below is the code I am using to create the specific instance of the segmented control. A frame initializer is required.
let seg = YSSegmentedControl(
frame: CGRect(
x: 0,
y: 0,
width: 0,
height: 0),
titles: [
"First",
"Second",
"Third"
],
action: {
control, index in
print ("segmented did pressed \(index)")
})
seg.delegate = self
view.addSubview(seg)
}
}
Thanks,
Nick
You should use or frame layout constructor which is old style, or use constraints.
I dont believe that this class does not have standart YSSegmentedControl() initializer.
let a: UIView = {
let a = UIView()
a.frame = CGRect(x: 0, y: 0, width: 20, height: 20)
return a
}()
I saw a lot of people's Swift source code defining let as this way. I just curious what is the benefit of this way?
In this case, there is no benefit, but if the variable in question were a value type then the benefit would be that you could perform some mutating setup code and still get a constant out of it.
It also lets you hide temporary variables that were only needed to initialize the constant, since they'll only exist inside the closure's scope.
I have this call:
myObject.perform(Selector("setCellSize:"), with: CGSize(width: 50.0, height: 50.0))
and inside class I have:
func setCellSize(_ size: CGSize) {
print(size)
self.itemSize = size
}
The method is correctly called, but it prints (0.0, 7.2911220195564e-304). What is wrong?
perform(_:with:) is a method from the NSObjectProtocol and
Sends a message to the receiver with an object as the argument.
In particular,
aSelector should identify a method that takes a single argument of type id. For methods with other argument types and return values, use NSInvocation.
If you really have to pass a CGSize via this method then you can
wrap it into a NSValue:
let value = NSValue(cgSize: CGSize(width: 50.0, height: 50.0))
myObject.perform(#selector(setCellSize(_:)), with: value)
func setCellSize(_ size: NSValue) {
print(size.cgSizeValue)
}
CGSize is not an object. It's a struct. You're printing gibberish passed to your setter. The function is only for objects.