How to Add Initializers in Extensions to Existing Uikit Classes Such as Uicolor

How to add initializers in extensions to existing UIKit classes such as UIColor?

You can't do it like this, you have to chose different parameter names to create your own initializers/ You can also make then generic to accept any BinaryInteger or BinaryFloatingPoint types:

extension UIColor {
convenience init<T: BinaryInteger>(r: T, g: T, b: T, a: T = 255) {
self.init(red: .init(r)/255, green: .init(g)/255, blue: .init(b)/255, alpha: .init(a)/255)
}
convenience init<T: BinaryFloatingPoint>(r: T, g: T, b: T, a: T = 1.0) {
self.init(red: .init(r), green: .init(g), blue: .init(b), alpha: .init(a))
}
}


let green1 = UIColor(r: 0, g: 255, b: 0, a: 255)  // r 0,0 g 1,0 b 0,0 a 1,0
let green2 = UIColor(r: 0, g: 1.0, b: 0, a: 1.0) // r 0,0 g 1,0 b 0,0 a 1,0

let red1 = UIColor(r: 255, g: 0, b: 0) // r 1,0 g 0,0 b 0,0 a 1,0
let red2 = UIColor(r: 1.0, g: 0, b: 0) // r 1,0 g 0,0 b 0,0 a 1,0

How can I create two initializers for a View in SwiftUI?

You can do it, like this way:

Convenience initializer are accessible in reference types! Not in value types (such as Struct)!



struct CustomView: View {

let title: String
let color: Color

init(title: String, color: Color) {
self.title = title
self.color = color
}

init(title: String) {
self.title = title
self.color = Color.black
}

var body: some View {

Text(title)
.foregroundColor(color)

}

}

use case:

struct ContentView: View {

var body: some View {

CustomView(title: "Hello")

CustomView(title: "Hello", color: Color.red)

}
}

Add more conversion units to existing apple classes of conversion

Just follow the documentation in Dimension, which is the superclass of UnitTemperature.

UnitTemperature's base unit is Kelvin. So I just had to look up the formula for converting Rankine to Kelvin, which is just a linear coefficient (degreesKelvin = degressRakine * 5/9), and plug that in:

extension UnitTemperature {
static var rankine = UnitTemperature(
symbol: "°R",
converter: UnitConverterLinear(coefficient: 5/9)
)
}

let celsius = Measurement(value: 5, unit: UnitTemperature.celsius)
let rankin = celsius.converted(to: .rankine)
print(rankin) // => 500.66999999999996 °R

Subclass an existing Swift Singleton

To extend

extension AWSclass {
func functionA () { ...}

}

usage

AWSclass.shared.functionA()

Overriding or extending UIColor to support certain protocols

I checked your situation, and I have also the impression that the compiler gets confused.

But there might be a solution. The following code compiles for me without problems:

public protocol MyProtocol {
init(myValue: Any) throws
}

class MyColor:UIColor {
convenience init(myValue: Any) throws {
self.init(red: 0, green: 0, blue: 0, alpha: 1)
}
}

EDIT:

I am sorry: Although this code compiles, it is missing the protocol.

Here is (hopefully) the correct code:

class MyColor:UIColor, MyProtocol {
required convenience init(myValue: Any) throws {
self.init(red: 0, green: 0, blue: 0, alpha: 1)
}
}

Swift 3.1 deprecates initialize(). How can I achieve the same thing?

Easy/Simple Solution

A common app entry point is an application delegate's applicationDidFinishLaunching. We could simply add a static function to each class that we want to notify on initialization, and call it from here.

This first solution is simple and easy to understand. For most cases, this is what I'd recommend. Although the next solution provides results that are more similar to the original initialize() function, it also results in slightly longer app start up times. I no longer think
it is worth the effort, performance degradation, or code complexity in most cases. Simple code is good code.

Read on for another option. You may have reason to need it (or perhaps parts of it).


Not So Simple Solution

The first solution doesn't necessarily scale so well. And what if you are building a framework, where you'd like your code to run without anyone needing to call it from the application delegate?

Step One

Define the following Swift code. The purpose is to provide a simple entry point for any class that you would like to imbue with behavior akin to initialize() - this can now be done simply by conforming to SelfAware. It also provides a single function to run this behavior for every conforming class.

protocol SelfAware: class {
static func awake()
}

class NothingToSeeHere {

static func harmlessFunction() {

let typeCount = Int(objc_getClassList(nil, 0))
let types = UnsafeMutablePointer<AnyClass>.allocate(capacity: typeCount)
let autoreleasingTypes = AutoreleasingUnsafeMutablePointer<AnyClass>(types)
objc_getClassList(autoreleasingTypes, Int32(typeCount))
for index in 0 ..< typeCount { (types[index] as? SelfAware.Type)?.awake() }
types.deallocate(capacity: typeCount)

}

}

Step Two

That's all good and well, but we still need a way to actually run the function we defined, i.e. NothingToSeeHere.harmlessFunction(), on application startup. Previously, this answer suggested using the Objective-C code to do this. However, it seems that we can do what we need using only Swift. For macOS or other platforms where UIApplication is not available, a variation of the following will be needed.

extension UIApplication {

private static let runOnce: Void = {
NothingToSeeHere.harmlessFunction()
}()

override open var next: UIResponder? {
// Called before applicationDidFinishLaunching
UIApplication.runOnce
return super.next
}

}

Step Three

We now have an entry point at application startup, and a way to hook into this from classes of your choice. All that is left to do: instead of implementing initialize(), conform to SelfAware and implement the defined method, awake().

How to have stored properties in Swift, the same way I had on Objective-C?

Associated objects API is a bit cumbersome to use. You can remove most of the boilerplate with a helper class.

public final class ObjectAssociation<T: AnyObject> {

private let policy: objc_AssociationPolicy

/// - Parameter policy: An association policy that will be used when linking objects.
public init(policy: objc_AssociationPolicy = .OBJC_ASSOCIATION_RETAIN_NONATOMIC) {

self.policy = policy
}

/// Accesses associated object.
/// - Parameter index: An object whose associated object is to be accessed.
public subscript(index: AnyObject) -> T? {

get { return objc_getAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque()) as! T? }
set { objc_setAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque(), newValue, policy) }
}
}

Provided that you can "add" a property to objective-c class in a more readable manner:

extension SomeType {

private static let association = ObjectAssociation<NSObject>()

var simulatedProperty: NSObject? {

get { return SomeType.association[self] }
set { SomeType.association[self] = newValue }
}
}

As for the solution:

extension CALayer {

private static let initialPathAssociation = ObjectAssociation<CGPath>()
private static let shapeLayerAssociation = ObjectAssociation<CAShapeLayer>()

var initialPath: CGPath! {
get { return CALayer.initialPathAssociation[self] }
set { CALayer.initialPathAssociation[self] = newValue }
}

var shapeLayer: CAShapeLayer? {
get { return CALayer.shapeLayerAssociation[self] }
set { CALayer.shapeLayerAssociation[self] = newValue }
}
}


Related Topics



Leave a reply



Submit