This question already has answers here:
Swift 4.2 Setter Getter, All paths through this function will call itself
(3 answers)
Why does Swift not allow stored properties in extensions?
(1 answer)
Closed 3 years ago.
I have a warning that I can not delete
All paths through this function will call itself
My code:
extension UIView {
var isLowAlpha: Bool {
get {
return self.isLowAlpha
}
set {
self.isUserInteractionEnabled = !newValue
self.alpha = newValue ? 0.3 : 1
}
}
}
I can not modify the code with this, because I have an error extension must not contain stored property ..:
extension UIView {
var isLowAlpha: Bool {
didSet {
self.isUserInteractionEnabled = !isLowAlpha
self.alpha = isLowAlpha ? 0.3 : 1
}
}
}
What is the solution?
One possible solution is to revert the process:
var isLowAlpha: Bool {
get {
return !isUserInteractionEnabled
}
set {
isUserInteractionEnabled = !newValue
alpha = newValue ? 0.3 : 1
}
}
or better, since you are not interested in the getter, make it a function:
func setIsLowAlpha(_ lowAlpha: Bool) {
self.isUserInteractionEnabled = !lowAlpha
self.lowAlpha = newValue ? 0.3 : 1
}
Anyway, looking at your code, you probably want to implement that a view is disabled. That's usually a task for UIControl subclasses, not UIView.
Also note the same can be implemented using a wrapper view:
class AlphaView: UIView {
var isLowAlpha: Bool = false {
didSet {
isUserInteractionEnabled = !isLowAlpha
alpha = isLowAlpha ? 0.3 : 1
}
}
}
And put your views inside.
In the first case you were recursively calling the variable's getter so it would never return. The way to fix this would be with a stored property _isLowAlpha, but unfortunately, as the second error mentions, Swift extensions cannot contain stored variables; they can only contain computed properties. If you really needed to add another property you would need to instead subclass UIView instead of making an extension.
However, in this case you can kind of cheat as long as you are not setting the UIView's alpha property elsewhere by directly using the alpha property:
extension UIView {
var isLowAlpha: Bool {
get {
return self.alpha == 0.3;
}
set {
self.alpha = newValue ? 0.3: 1
self.isUserInteractionEnabled = !newValue
}
}
}
Related
How do I change the button background color when the button is highlighted with swift,then I also want to know . How can I make this background color last for a period of time instead of clicking it to disappear immediately? For example, I want it to disappear 2 seconds after clicking. I checked some information and couldn't find a way. All I can think of is to write a click event, then change the background color of the button and set a time to change it back
I found the method. As a novice, I can't fully understand it, but it can be used. Friends with similar problems can refer to it
class MyButton : UIButton {
#IBInspectable var normalBackgroundColor: UIColor? {
didSet {
backgroundColor = normalBackgroundColor
}
}
#IBInspectable var highlightedBackgroundColor: UIColor?
override var isHighlighted: Bool {
didSet {
if oldValue == false && isHighlighted {
highlight()
} else if oldValue == true && !isHighlighted {
unHighlight()
}
}
}
func highlight() {
animateBackground(to: highlightedBackgroundColor, duration: highlightDuration)
}
func unHighlight() {
animateBackground(to: normalBackgroundColor, duration: highlightDuration)
}
var highlightDuration: TimeInterval = 1
private func animateBackground(to color: UIColor?, duration: TimeInterval) {
guard let color = color else { return }
UIView.animate(withDuration: highlightDuration) {
self.backgroundColor = color
}
} }
You can create a new file and write the above code
Then bind the button class as shown in the figure
Finally, your button has the content you want in the right property panel
You can modify the animation time by changing the value of highlightduration
I have problem with xcframwork.when i create xcframwork my properties not display in my main project storyboard. When i create framework it display all properties in my storyboard.
I have created Following code
#objc
public extension UIView {
// Note : Corner radius and shadow not work both side by side so you need to outlet and set layer radius
// other wise you can set layer.cornerradius in user defines
//MARK: Border COLOR
#IBInspectable
var borderColor: UIColor? {
get {
return self.borderColor
}
set {
self.layer.borderColor = newValue?.cgColor
}
}
}
1 using framework
It display all Properties
now i created xcframework. all properties not display Now i am stuck with this.
anyone help me how can i create xcframwork and display all properties like normal framework. Please help me on this.
The properties in your framework are internal. When no access modifier is specified then Swift defaults to internal.
enter image description here
so in your code:
var radTopLeft:CGFloat = 0 {
didSet {
self.setNeedsLayout()
}
}
is equivalent to:
internal var radTopLeft:CGFloat = 0 {
didSet {
self.setNeedsLayout()
}
}
Therefore no code outside the framework can access this property. In order to make it accessible to the framework consumer you have to mark the property public. i.e.
public var radTopLeft:CGFloat = 0 {
didSet {
self.setNeedsLayout()
}
}
Test it out: https://drive.google.com/file/d/1_WSGKRKNt4lytrVEuozn8W4WYRR6nPif/view?usp=sharing
I am trying to use IBInspectable to add borders to my views.
extension UIView {
private func getBorder(integer: Int) -> UIRectEdge {
if integer == 1 {
return .top
} else if integer == 2 {
return .left
} else if integer == 3 {
return .right
} else if integer == 4 {
return .bottom
}
return .all
}
#IBInspectable var border: Int? {
get {
return self.border
}
set (value) {
self.border = value
for v in addBorder(edges: self.getBorder(integer: self.border!)) {
self.addSubview(v)
}
}
}
#IBInspectable var borderColor: UIColor? {
get {
return self.borderColor
}
set (value) {
self.borderColor = value //EXC_BAD_ACCESS here
for v in addBorder(edges: self.getBorder(integer: self.border!), color: borderColor!) {
self.addSubview(v)
}
}
}
private func addBorder(edges: UIRectEdge, color: UIColor = UIColor.white, thickness: CGFloat = 1) -> [UIView] {
...
}
}
The crash occurs on the line self.borderColor = value (in the set for the borderColor).
All it says in the debug log is (lldb). The crash itself says:
Thread 1: EXC_BAD_ACCESS (code=2, address=0x7fff53cc5fe8)
Here is my storyboard:
How can I fix this issue? Thanks!
You have an infinite recursion there, that is causing the crash. Basically within the setter of borderColor you're calling the setter for the same property, resulting the infinite recursion.
This happens because class extensions are not allowed to have stored properties, so Swift doesn't generate a backstore for your property, instead it treats it like a computed property, and calls the setter whenever you try to set the property.
There are two solutions that I can think of at this time, that will solve your problem:
Subclass UIView, add the two properties there, update the class in IB to match the name of your new class.
Use associated objects in your UIView accessors (objc_setAssociatedObject()/ objc_getAssociatedObject()) instead of direct iVar reference. You will not need to subclass and to update your xibs, however this solution is a little bit messier than the first one.
So I'm fairly new to the whole UIAppearance approach to doing things, and doing it with swift. Hurray for not a ton of documentation out there.
I'm trying to set my border radius through UIAppearance with something along the lines of:
CircleButton.appearance.roundBorderRadius = 9
My CircleButton class implementation:
public class CircleButton : UIButton{
#nonobjc var roundBorderRadius: CGFloat? {
get { return self.layer.cornerRadius }
set {
self.layer.cornerRadius = newValue!
}
}
}
And I hook everything up in Storyboard to a ViewController that contains a CircleButton. No Compilation or Build errors.
However, at runtime I'm getting a:
"Thread 1: EXC_BAD_ACCESS" error on:
CircleButton.appearance.roundBorderRadius = 9
Any advice?
Remove #nonobjc and add dynamic, then change the type from CGFloat? to CGFloat and remove the ! after newValue in the setter, like so:
public class CircleButton: UIButton {
dynamic var roundBorderRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
}
}
}
I can’t figure out how to incorporate a design pattern in to my Swift class which has a property with the following requirements:
Property with default value and is IBInspectable
accompanying setProperty:animated: method
All of the ways I’ve tried require a separate private ‘instance' variable e.g. _property, like below:
#IBInspectable var progress: CGFloat = 0.5 {
didSet {
_progress = progress
setNeedsDisplay()
}
}
private var _progress: CGFloat = 0.5
func setProgress(progress: CGFloat, animated: Bool)
{
if _progress == progress
{
return
}
if animated
{
// Animate changes
// [Animation code]
}
else
{
// No need to animate changes
setNeedsDisplay()
}
titleLabel?.text = "\(NSInteger(progress * 100))%"
// Update value
_progress = progress
}
This doesn’t account for getting the property value though. As a property cannot have a get and didSet method.
So what is the correct way of having a property which is IBInspectable and can be set in the setAnimated method without automatically updating, bypassing the animation?