Override class variable declared in the superclass's extension in Swift - swift

Is it a bug of Swift 5.0.1 or Xcode?
This is in the playground with Xcode 10.2.1.
The codes are:
extension UIColor {
#objc class var myGolden: UIColor {
return self.init(red: 1.000, green: 0.894, blue: 0.541, alpha: 0.900)
}
}
print(UIColor.myGolden)
class MyUIColor: UIColor {
override class var myGolden: UIColor {
return super.init(red: 1.000, green: 0.894, blue: 0.541, alpha: 0.750)
}
}
print(MyUIColor.myGolden)
The playground does not indicate any error for the class MyUIColor
The output is:
UIExtendedSRGBColorSpace 1 0.894 0.541 0.9
libc++abi.dylib: terminating with uncaught exception of type NSException
and the runtime error says:
error: Execution was interrupted, reason: signal SIGABRT. The process
has been left at the point where it was interrupted, use "thread
return -x" to return to the state before expression evaluation.

The problem isn't the class variable override, is instead the improper use of self.init and super.init. You should change the code as follows:
extension UIColor {
#objc class var myGolden: UIColor {
return UIColor(red: 1.000, green: 0.894, blue: 0.541, alpha: 0.900)
}
}
print(UIColor.myGolden)
class MyUIColor: UIColor {
override class var myGolden: UIColor {
return UIColor(red: 1.000, green: 0.894, blue: 0.541, alpha: 0.750)
}
}
print(MyUIColor.myGolden)

Changing the self.init and super.init calls to UIColor.init fixes the issue. You should only call self.init and super.init from convenience initialisers or subclass initialisers respectively, when creating an instance of your class in a computed property or any other functions, you should be calling the init methods using the type name rather than self or super.
extension UIColor {
#objc class var myGolden: UIColor {
return UIColor(red: 1.000, green: 0.894, blue: 0.541, alpha: 0.9)
}
}
print(UIColor.myGolden)
class MyUIColor: UIColor {
override class var myGolden: UIColor {
return UIColor(red: 1.000, green: 0.894, blue: 0.541, alpha: 0.75)
}
}
print(MyUIColor.myGolden)

Related

Swift, SwiftUI - .getRed(&red, green: &green, blue: &blue, alpha: &alpha)

I am following Stanfords' CS193p Developing Apps for iOS online course.
I'm trying to do the Assignment 6 Memorize.pdf.
It says to use this code below ⬇️, but it gives me always white color. Is there a bug somewhere? Please help.
import SwiftUI
struct RGBAColor: Codable, Equatable, Hashable {
let red: Double
let green: Double
let blue: Double
let alpha: Double
}
extension Color {
init(rgbaColor rgba: RGBAColor) {
self.init(.sRGB, red: rgba.red, green: rgba.green, blue: rgba.blue, opacity: rgba.alpha)
}
}
extension RGBAColor {
init(color: Color) {
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
if let cgColor = color.cgColor {
UIColor(cgColor: cgColor).getRed(&red, green: &green, blue: &blue, alpha: &alpha)
}
self.init(red: Double(red), green: Double(green), blue: Double(blue), alpha: Double(alpha))
}
}
import SwiftUI
struct ContentView: View {
static let rgbaColorRed = RGBAColor(color: Color.red)
static let thisShouldBeRed = Color(rgbaColor: rgbaColorRed)
var body: some View {
Text("Hello, world!")
.padding()
.foregroundColor(ContentView.thisShouldBeRed) // why white here, not red???
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
As the cgColor property's documentation says:
For a dynamic color, like one you load from an Asset Catalog using init(_:bundle:), or one you create from a dynamic UIKit or AppKit color, this property is nil.
Color.red is actually a dynamic color:
A context-dependent red color suitable for use in UI elements.
So Color.red.cgColor is nil, causing the getRed(_:green:blue:alpha:) call to not run, and the red, green, blue, alpha local variables remain 0. So the color you got is not "white", but "transparent".
You can actually create a UIColor directly from Color, without going through CGColor:
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
// note here:
UIColor(color).getRed(&red, green: &green, blue: &blue, alpha: &alpha)
self.init(red: Double(red), green: Double(green), blue: Double(blue), alpha: Double(alpha))

How to use UIColor as RawValue of an enum type in Swift

I was trying to declare an enum type using UIColor as the raw value. Here is the code:
enum SGColor: UIColor {
case red = #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1)
case green = #colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1)
case purple = #colorLiteral(red: 0.5568627715, green: 0.3529411852, blue: 0.9686274529, alpha: 1)
}
But I got two errors in the first line:
'SGColor' declares raw type 'UIColor', but does not conform to
RawRepresentable and conformance could not be synthesized
Do you want to add protocol stubs? Fix it
Raw type 'UIColor' is not expressible by any literal
If I took the first advice, Xcode will add typealias RawValue = <#type#> at the beginning inside of the parentheses. But I am not sure what to do with it.
And if I were to address the second error, how do I change the raw type to a literal?
After some digging, I found a post by Ole Begemann that mentions how to make a customized color enumeration collection, which is SGColor in this question, conform to the RawRepresentable protocol.
Basically, while Xcode is smart to suggest me to fix the problem by explicitly telling it the raw type (as seen in the first error in the question), it is still not intelligent enough to figure out how to do that for color literals, or UIColor.
Ole Begemann mentioned a manual conformance will fix this. And he gave a detailed explanation as of how to do it.
While he used UIColor color objects (such as UIColor.red), I tried and tested the feasibility of using color literals, since in general, they are more visually direct and more customizable.
enum SGColor {
case red
case green
case purple
}
extension SGColor: RawRepresentable {
typealias RawValue = UIColor
init?(rawValue: RawValue) {
switch rawValue {
case #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1): self = .red
case #colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1): self = .green
case #colorLiteral(red: 0.5568627715, green: 0.3529411852, blue: 0.9686274529, alpha: 1): self = .purple
default: return nil
}
}
var rawValue: RawValue {
switch self {
case .red: return #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1)
case .green: return #colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1)
case .purple: return #colorLiteral(red: 0.5568627715, green: 0.3529411852, blue: 0.9686274529, alpha: 1)
}
}
}

Swift right CustomColor class declaration

because of strange color solutions in swift i needed to make customcolor class. And i dont know am i doing right.
i have a class CustomColors()
and usage: color = CustomColors().black and works perfectly
but i want to make use like: color = CustomColors(.Black)
i cant do like this:
init(_ Color: Colors)
{
switch Colors
case .Black
return UIColor(r:255,g:255,b:255,a:255)
}
A lot of things i dont know. Can someone put me on right solution? Thank you.
Instead of custom class you can use an UIColor extension with convenience initializer, as such:
extension UIColor {
convenience init(color: Colors) {
switch color {
case .black:
self.init(red: 1, green: 1, blue: 1, alpha: 1)
case .white:
self.init(red: 1, green: 1, blue: 1, alpha: 1)
}
}
}
But I think its better if you pre-define your colors using struct's static properties, as such:
struct Theme {
static let colorOne = UIColor(red: 0.952941, green: 0.952941, blue: 0.952941, alpha: 1.0) // F3F3F3
static let colorTwo = UIColor(red: 0.203922, green: 0.203922, blue: 0.203922, alpha: 1.0) // 343434
// and so on...
}
Usage
UILabel().backgroundColor = Theme.colorOne
UILabel().textColor = Theme.colorTwo
you can add extension to UIColor class with your custom colors:
import UIKit
extension UIColor {
static var mediumTurquoise: UIColor {
return UIColor(red:0.31, green:0.82, blue:0.8, alpha:1)
}
}
please be sure that the value of RGB between 0.0 and 1.0.
you can user the custom color as UIolor.mediumTurquoise

Set UIColor in storyboard from variable/constant [duplicate]

This question already has answers here:
How to change dynamically color used in UIStoryboard
(2 answers)
Closed 4 years ago.
How do I set, let's say a text color on a UILabel, to a color defined in one of my classes like:
func mainAppColor() -> UIColor {
return UIColor(red: 0.2, green: 0.3, blue: 0.4, alpha: 1)
}
or
let mainAppColor = UIColor(red: 0.2, green: 0.3, blue: 0.4, alpha: 1)
in storyboard.
If your method is declared in some other class like:
class TextColorClass {
func mainAppColor() -> UIColor {
return UIColor(red: 0.2, green: 0.3, blue: 0.4, alpha: 1)
}
}
Then you can use it by make instance of that class this way:
let classInstance = TextColorClass()
yourLBL.textColor = classInstance.mainAppColor()
If it is declared like:
class TextColorClass {
let mainAppColor = UIColor(red: 0.2, green: 0.3, blue: 0.4, alpha: 1)
}
Then you can use it like:
let classInstance = TextColorClass()
yourLBL.textColor = classInstance.mainAppColor
If that method is declare in same class suppose in ViewController class then you can use it this way:
override func viewDidLoad() {
super.viewDidLoad()
yourLBL.textColor = mainAppColor()
}
func mainAppColor() -> UIColor {
return UIColor(red: 0.2, green: 0.3, blue: 0.4, alpha: 1)
}
UPDATE:
If you want to set any property from storyboard you can use #IBInspectable as shown in below example code:
import UIKit
#IBDesignable
class PushButtonView: UIButton {
#IBInspectable var fillColor: UIColor = UIColor.greenColor()
#IBInspectable var isAddButton: Bool = true
override func drawRect(rect: CGRect) {
}
}
And assign this class to your button.like shown into below Image:
And if you go to the Attribute Inspector you can see custom property for that button.
Now you can set it as per your need.
For more Info refer this tutorial:
http://www.raywenderlich.com/90690/modern-core-graphics-with-swift-part-1

Swift: using member constant as default value for function parameter

I have a swift class, in which I am trying to pass a default value for a function parameter:
class SuperDuperCoolClass : UIViewController {
// declared a constant
let primaryColor : UIColor = UIColor(red: 72.0/255.0, green: 86.0/255.0, blue: 114.0/255.0, alpha: 1.0)
// compilation error at below line: SuperDuperCoolClass.Type does not have a member named 'primaryColor'
func configureCheckmarkedBullet(bullet: UIButton, color: UIColor = primaryColor){
// some cool stuff with bullet and primaryColor
}
}
As stated above, if I try to use constant as default value for function parameter, compiler complains with below error:
SuperDuperCoolClass.Type does not have a member named 'primaryColor'
but if I assign the RHS value directly like this, it does not complain :-/ :
func configureCheckmarkedBullet(bullet: UIButton, color: UIColor = UIColor(red: 72.0/255.0, green: 86.0/255.0, blue: 114.0/255.0, alpha: 1.0)) {
// now I can do some cool stuff
}
Any ideas on how can I silence the above compilation error?
You have to define the default value as a static property:
class SuperDuperCoolClass : UIViewController {
static let primaryColor : UIColor = UIColor(red: 72.0/255.0, green: 86.0/255.0, blue: 114.0/255.0, alpha: 1.0)
func configureCheckmarkedBullet(bullet: UIButton, color: UIColor = primaryColor){
}
}
The above code compiles with Swift 1.2 (Xcode 6.3) which added support
for static computed properties. In earlier versions, you can define
a nested struct containing the property as a workaround (compare
Class variables not yet supported):
class SuperDuperCoolClass : UIViewController {
struct Constants {
static let primaryColor : UIColor = UIColor(red: 72.0/255.0, green: 86.0/255.0, blue: 114.0/255.0, alpha: 1.0)
}
func configureCheckmarkedBullet(bullet: UIButton, color: UIColor = Constants.primaryColor){
}
}
Since primaryColor is an instance variable it cannot be accessed until an instance is created from this class and since the function is part of the class definition you will get this error as primaryColor cannot access at that time.
You can either use MartinR approach or use your approach with the desired color:
func configureCheckmarkedBullet(bullet: UIButton, color: UIColor = UIColor(red: 72.0/255.0, green: 86.0/255.0, blue: 114.0/255.0, alpha: 1.0)) {
// now I can do some cool stuff
}