unlike class var, where they can overridden in subclasses, I believe same applies to static as well but unfortunately not. Here's an example
public class A {
private static let NAME: String = "A"
}
public class B: A {
private static let NAME: String = "B" //error
}
in my opinion static means association with that particular class, so in the above example B should get it's own space to redefine that variable as it's associated to B only, I'm reverting to stored properties unless someone has a better solution.
You can use computed properties:
class A {
class var Name: String {
return "A"
}
}
class B: A {
override class var Name: String {
return "B"
}
}
Usage:
print(A.Name) // "A"
print(B.Name) // "B"
The documentation says:
“
static
” methods and properties are now allowed in classes (as an alias for “
class final
”).
So it is final, which means you cannot override it.
As suggested, you cannot override static variables but can use class (static) function to override.
class A {
class func StaticValue() -> AnyObject {
return "I am a String"
}
}
class B: A {
override class func StaticValue() -> AnyObject {
return 2
}
}
You can have computed class properties:
public class A {
class var NAME: String {
return "A"
}
}
public class B {
class var NAME: String {
return "B"
}
}
If need be, you could even "branch" to a stored property in the subclass:
public class A {
// Needs to be overriden in subclass
class var NAME: String {
return "A"
}
}
public class B {
class var NAME: String {
return B.storedName
}
static var storedName: String = defineName()
func defineName() -> String {
// You could do something more complex here
return "B"
}
}
Related
Is there a way to create accessors of inner object properties without having boilerplate?
Here's an example of a class with the boilerplate
public class Foo {
internal let bar: Bar
internal init(bar: Bar) {
self.bar = bar
}
private struct Bar: Codable {
let id: Int
let name: String
}
// MARK: - Boilerplate
public var id: Int {
return self.bar.id
}
public var name: String {
return self.bar.name
}
}
// Usage
do {
let bar: Bar = try data.decoded()
let foo = Foo(bar: bar)
print(foo.id)
print(foo.name)
} catch {
...
}
Is there a way to do this without having to write the boilerplate? For larger objects with more properties this could be really helpful
Take Note: The Access Control Modifiers are important
New in Swift 5.1, you can use dynamic member lookup with a key path. This works brilliantly for this sort of "has-a" situation, because key paths maintain full type checking. Here's a simplified example (with no attempt to mirror your actual situation):
struct Dog {
let name : String
}
#dynamicMemberLookup
struct Kennel {
let dog : Dog
subscript(dynamicMember kp:KeyPath<Dog,String>) -> String {
self.dog[keyPath:kp]
}
}
The result is that, given a Kennel k, we can get k.name as a way of getting k.dog.name.
But saying k.xxx would be illegal, because a Dog has no String xxx property; that's what I mean when I say that full type checking is maintained.
The old way would be to use protocols. That way you can use protocol extension to inject the boilerplate.
protocol HasNameAndId {
var id: Int {get}
var name: String {get}
}
protocol WrapperOfHasNameAndId {
associatedtype T : HasNameAndId
var bar: T {get}
}
extension WrapperOfHasNameAndId { // boilerplate
var id: Int {
return self.bar.id
}
var name: String {
return self.bar.name
}
}
// ==============
struct Bar: HasNameAndId {
let id: Int
let name: String
}
class Foo : WrapperOfHasNameAndId {
let bar: Bar
init(bar: Bar) {
self.bar = bar
}
}
// =======
let f = Foo(bar: Bar(id: 1, name: "howdy"))
print(f.id) // 1
print(f.name) // "howdy"
I have a UnitDimension class given by:
class UnitDimension: {
var symbol: String
init(symbol: String) {
self.symbol = symbol
}
}
and a UnitVolume subclass of this class:
class UnitVolume: UnitDimension {
static let liter = UnitVolume(symbol: "L")
}
I want to have a protocol UnitDimensionHandler that allows me to perform some simple functions. Firstly it must have an allUnits variable:
protocol UnitDimensionHandler: class {
static var allUnits: [UnitDimension] { get }
}
Is it possible to have allUnits a generic type of array that must be a subclass of UnitDimension? I could then implement it in UnitVolume as follows:
extension UnitVolume: UnitDimensionHandler {
static var allUnits: [UnitVolume] {
return [liter]
}
}
I then want to include a function that also allows me to use a generic subclass type that initiates a UnitDimension instance:
extension UnitDimensionHandler {
static func unit(for symbol: String) -> UnitDimension? {
return allUnits.first() { $0.symbol == symbol }
}
}
such that UnitVolume.unit(for: "L") returns an optional UnitVolume rather than an optional UnitDimension.
Thanks for any help.
Yes it is possible, using associatedtype:
protocol UnitDimensionHandler: class {
// here we define `generic` type variable `Dimension`, and specify it do be descendant of `UnitDimension`
associatedtype Dimension: UnitDimension
// and use it here, instead of `UnitDimension`
static var allUnits: [Dimension] { get }
}
And
extension UnitDimensionHandler {
// same `UnitDimension` -> `Dimension` replacement
static func unit(for symbol: String) -> Dimension? {
return allUnits.first() { $0.symbol == symbol }
}
}
I would like to create a class with a static property that subclasses can override, which would be used to initialize instances. So far, I've tried to accomplish this like this:
import Cocoa
class A: NSObject {
class var staticProperty: String {
return "A"
}
var property: String = A.staticProperty
}
class B: A {
override class var staticProperty: String {
return "B"
}
}
This does not work, since B().property still returns "A". How could I change this code so that property contains the value specified by the subclass? Any help would be appreciated!
Edit
I would like to initialize property with the value of staticProperty, so this could also look like this:
var property: SomeClass = SomeClass(A.staticProperty)
But then, this initialization should still use "A" for class A, and "B" for class B.
Edit 2 (After #RakeshaShastri's comment)
For my specific use-case, I need property to be stored (so not computed) and non-lazy.
Edit 3
In short, I'm trying to build a Realm model class which has a few to-many relationships to other models. For these models (which are quite similar), I'm trying to create a superclass which contains the shared functionality, amongst which is also the inverse relationship. Therefore, I want to have a static property which contains the key in the first model to either of the other models, and then initialize a LinkingObjects property using this key name. Since Realm does not allow this to be lazy or computed, I cannot use these functionalities here.
If you inherit from NSObject why not using it ?
import Cocoa
class A: NSObject {
var property: String
public override init() {
let str = type(of: self).perform(#selector(getter: type(of: self).staticProperty))?.takeUnretainedValue() as! String
property = str
}
#objc class var staticProperty: String {
return "A"
}
}
class B: A {
override class var staticProperty: String {
return "B"
}
}
You can do this with this aproach
class A {
var prop: String{
return "A"
}
}
class B: A {
override var prop: String{
return "B"
}
}
print(A().prop) // "PRINTS A"
print(B().prop) // "PRINTS B"
A.staticProperty will use static dispatch and will always point to A's class property. You need dynamic dispatch here, aka type(of: self).
However, self needs an instance to work with, thus var property: String = type(of: self.staticProperty won't compile.
However, lazy properties can work around this limitation, so you could declare property as a lazy one:
class A: NSObject {
class var staticProperty: String {
return "A"
}
private(set) lazy var property: String = { type(of: self).staticProperty }()
}
class B: A {
override class var staticProperty: String {
return "B"
}
}
print(B().property) // B
P.S. the private(set) part is just something I usually do, I rarely allow extrinsic factors to change my object.
Update As #MartinR has pointed out, lazy is not a choice for the OP. An alternative solution that doesn't use a lazy var is to use a "shadowing" property:
class A: NSObject {
class var staticProperty: String {
return "A"
}
private var _property: String?
var property: String {
get {
return _property ?? type(of: self).staticProperty
}
set {
_property = newValue
}
}
}
class B: A {
override class var staticProperty: String {
return "B"
}
}
let b = B()
print(b.property) // B
b.property = "B'"
print(b.property) // B'
I want to write the following in Swift:
class A
{
class let x = 0
func print_class_property()
{
print(type(of: self).x)
}
}
class B:A
{
overriding class let x = 1
}
class C:A
{
overriding class let x = 5
}
A().print_class_property() // 0
B().print_class_property() // 1
C().print_class_property() // 5
But of course, this doesn’t compile.
Instead, I can demote the class property to a variable instance property that’s overwritten in the subclass initializers, but this allocates storage for x in every instance of A, B, or C. In addition you lose the guarantee that x never changes across the lifetime of the object.
How do I store constants at the class level, that can be shared by all instances of a subclass?
Unfortunately Swift (as for now) cannot have class stored properties that can be overriden. But can have class computed properties, which are overridable.
You can write something like this:
class A
{
class var x: Int {
return 0
}
func print_class_property()
{
print(type(of: self).x)
}
}
class B:A
{
override class var x: Int {
return 1
}
}
class C:A
{
override class var x: Int {
return 5
}
}
A().print_class_property() //->0
B().print_class_property() //->1
C().print_class_property() //->5
ADDITION
If you do not desire such re-evaluation as noted in comments, you may need to have some another static property.
For example:
class A
{
class var x: SomeLargeObject {
struct My {
static let obj = SomeLargeObject("abc", 0)
}
return My.obj
}
func print_class_property()
{
print(type(of: self).x)
}
}
class B:A
{
override class var x: SomeLargeObject {
struct My {
static let obj = SomeLargeObject("def", 1)
}
return My.obj
}
}
class C:A
{
override class var x: SomeLargeObject {
struct My {
static let obj = SomeLargeObject("ghi", 5)
}
return My.obj
}
}
I'm building a simple state engine, where I want a collection of states that I can move between.
The way I'd like to go about this is to have an enumeration of states that are possible that also define the corresponding class that represents that state, so that I can construct the state dynamically if I decide to move to that state.
In the code below I've tried building an enum of State objects which works fine. Where I get stuck is, how can I access the values of this enum as types that I can call a static constructor method from? In the code below the error I get is that the attempt to call moveToState with an enum value does not represent the StartupStates type, which it seems to...
So the question is really, why does this not work, or what other way can I have an enum of class types and/or class level (static) methods to call a constructor from?
public enum StartupStates<State> {
case Start(StartState)
case DownloadFiles(DownloadFilesState)
}
public protocol State {
var stateEngine : StateEngine {get set}
}
public class StateEngine
{
var currentState : State?
public func moveToState(newState : StartupStates<State>)
{
}
}
public class StartState : BaseState
{
func doStateTasks()
{
// Move to next state, downloading files
// ERROR IS HERE:
// "Cannot convert file of type '(DownloadFileState)->StartupStates<...>' to expected argument type 'StartupStates<State>'"
stateEngine.moveToState(StartupStates.DownloadFiles)
}
}
public class DownloadFilesState : BaseState
{
}
public class BaseState : State {
public var stateEngine : StateEngine
required public init( stateEngine : StateEngine ) {
self.stateEngine = stateEngine
}
public static func stateCreator(stateEngine : StateEngine) -> Self {
return self.init( stateEngine: stateEngine )
}
}
String Solution:
You may be able to use NSClassFromString to your advantage in this scenario. Consider the following example:
enum State: String {
case StartState = "StartClass"
case DownloadState = "DownloadClass"
case BaseState = "BaseClass"
var klass: AnyClass {
return NSClassFromString(self.rawValue)!
}
}
Let me know if this sort of solution is what you are looking for.
Alternative Solution:
If you want to not depend on typing the string solutions then you'll need to have a simple switch statement for the class types:
class StartClass {}
class DownloadClass {}
class BaseClass {}
enum State {
case StartState
case DownloadState
case BaseState
var klass: AnyClass {
switch self {
case .StartState:
return StartClass.self
case .DownloadState:
return DownloadClass.self
case .BaseState:
return BaseClass.self
}
}
}
How about this:
class StartState : BaseState {
func doStateTasks() {
let download = DownloadFilesState(stateEngine: StateEngine())
stateEngine.moveToState(.DownloadFiles(download))
}
}
Because DownloadFiles enum need a DownloadFilesState object as define in enum.
How about using a completion handler instead of a class type?
protocol MyProtocol {}
class StartClass: MyProtocol {}
class DownloadClass: MyProtocol {}
class BaseClass: MyProtocol {}
enum State {
case StartState
case DownloadState
case BaseState
var completionHandler: () -> MyProtocol {
switch self {
case .StartState:
return { return StartClass() }
case .DownloadState:
return { return DownloadClass() }
case .BaseState:
return { return BaseClass() }
}
}
}
Accessing the initialized class from enum value.
var myState: State = .StartState
myState.completionHandler { initializedStartClass in
InitializedStartClass.methods....
}