Using an overriden static property during initialization - swift

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'

Related

Swift Combine - How to subscribe to nested Observable Objects

This is a slightly more abstract version of this question. In the app, these nested Observable Objects are indeed used in a view (so I'd rather use Observable Objects rather than straight Publishers). However, I would like to be able to simply subscribe to the view models in order to test them. The protocol is there so I can mock out Nested in tests.
This is the basic setup:
protocol NestedProtocol: AnyObject {
var string: String { get set }
}
class Nested: ObservableObject, NestedProtocol {
#Published var string = ""
}
class Parent: ObservableObject {
#Published var nested: NestedProtocol
init(nested: NestedProtocol) {
self.nested = nested
}
}
var sinkHole = Set<AnyCancellable>()
let nested = Nested()
let parent = Parent(nested: nested)
parent.$nested.sink { newValue in
print("NEW VALUE \(newValue.string)")
}.store(in: &sinkHole)
Then this command
nested.string = "foo1" outputs "NEW VALUE ", which is expected as the initial value of nested. I would like it to output "NEW VALUE foo1". (TIL published variables seem to be current value publishers.)
Of course I could do
nested.string = "foo1"
parent.nested = nested
and I would get "NEW VALUE foo1", but that's smelly.
I tried
protocol NestedProtocol: ObservableObject {
var string: String { get set }
}
class Nested<T>: ObservableObject where T: NestedProtocol {
...
But in real life, I would like nested to declare some static constants, which is not allowed in generic types. So that doesn't work.
From the cited question/answer, I also tried combinations of
Parent
init() {
nested.objectWillChange.sink { [weak self] (_) in
self?.objectWillChange.send()
}.store(in: sinkHole)
}
Nested
init() {
string.sink { [weak self] (_) in
self?.objectWillChange.send()
}.store(in: sinkHole)
}
No dice. Those methods were getting called but that outer-level sink was still just returning "NEW VALUE "
I also tried calling
parent.nested.string = "foo1"
So now I'm modifying the parent, and that should work, right? Wrong.
There's a bunch to unpack here.
First, you might know that if a property is a value-type, like a struct or String, then marking it as #Published just works:
class Outer {
#Published var str: String = "default"
}
let outer = Outer()
outer.$str.sink { print($0) }
outer.str = "changed"
Will output:
default
changed
Your question, however, is about a nested observable object, which is a reference type. So, the above wouldn't work with a reference-type.
But in your example you're using a protocol as an existential (i.e. in place of an eventual instance), and as you noted, without inheriting from AnyObject, then it really behaves like a value-type:
protocol InnerProtocol {
var str: String { get set }
}
class Inner: InnerProtocol {
#Published var str: String = "default"
}
class Outer {
#Published var inner: InnerProtocol
init(_ inner: InnerProtocol) { self.inner = inner }
}
let inner = Inner()
let outer = Outer(inner)
outer.$inner.sink { print($0.str) }
outer.inner.str = "changed"
This would also output:
default
changed
which looks like what you wanted, but in fact it doesn't really "observe" any changes in the nested object. When you do outer.inner.str, it has value-type semantics, so it's as-if you re-assigned the .inner property. But if you are truly interested in observing changes of the object itself, then this approach wouldn't work at all. For example:
nested.str = "inner changed"
would not cause an output. Neither would there be an output if the inner object changed its own property, e.g.:
init() {
DisplatchQueue.main.asyncAfter(.now() + 1) {
self.str = "async changed"
}
}
So, it's unclear what exactly you're trying to achieve. If you want to observe a reference type property, you'd need to observe it directly.
class Inner: ObservableObject {
#Published var str: String
//...
}
class Outer: ObservableObject {
var inner: Inner
//...
}
//...
outer.inner.$str.sink { ... }
// or
outer.inner.objectWillChange.sink { ... }
You can achieve this with a protocol too, if you insist:
protocol InnerProtocol: ObservableObject {
var str: String { get set }
}
class Inner: InnerProtocol {
#Published var str: String = "default"
}
class Outer<T: InnerProtocol>: ObservableObject {
var inner: T
init(_ inner: T) { self.inner = inner }
}
let inner = Inner()
let outer = Outer(inner)
outer.inner.$str.sink { ... }
inner.str = "changed"
This took me hours and I stumbled upon it by accident while trying to modify my protocol in various ways.
Lesson 1:
protocol NestedProtocol: AnyObject {
var string: String { get set }
}
should be
protocol NestedProtocol {
var string: String { get set }
}
Why? I'm not sure. Apparently, if the Parent cannot assume that the published object is a class, then it watches modifications on it more closely? My instinct tells me the exact opposite, but it goes to show how much I can trust my instinct.
Lesson 2:
Indeed my 4th idea was correct and you need to name the parent in the nested object modification:
nested.string = "foo1"
should be
parent.nested.string = "foo1"
Again, they're all classes so it goes slightly against my understanding, but I don't know all the magic that goes on under #Published.
The final complete version looks like this:
protocol NestedProtocol {
var string: String { get set }
}
class Nested: ObservableObject, NestedProtocol {
#Published var string = ""
}
class Parent: ObservableObject {
#Published var nested: NestedProtocol
init(nested: NestedProtocol) {
self.nested = nested
}
}
var sinkHole = Set<AnyCancellable>()
let nested = Nested()
let parent = Parent(nested: nested)
parent.$nested.sink { newValue in
print("NEW VALUE \(newValue.string)")
}.store(in: &sinkHole)
and
nested.string = "foo1"
parent.nested.string = "foo2"
returns
"NEW VALUE "
"NEW VALUE foo2"

is it possible to declare Computed property and Observers with class Label type?

I am new in swift anyone help me to understand
what is the purpose ? I should be used class label type !
is it possible to declare Computed property and Observers with class Label type ?
both ,either or neither ?
thank you
Type Properties can be created using either static or class keyword
Computed properties can be created using class as well as static keyword.
Property observers are not allowed using class keyword. They can only be used with static.
Example:
class First
{
class var x : Int{
return 3
}
static var y : Int{
return 2
}
// error: class stored properties not supported in classes
// class var z = 10 {
// willSet{
// print(newValue)
// }
// }
static var w = 30 {
willSet{
print(newValue)
}
}
}
Class Computed Property
You can declare a class computed property
class Foo {
class var p0: String { return "p0" }
}
Class Static Stored property
It is somehow possible but you need to use the static keyword
class Foo {
static var p0: String = "p0" {
didSet {
print("Did set p0")
}
}
}

Get object type from optional?

Is it possible to get the object type from an optional?
For example, if I have a class that has a property that is an optional string, can I somehow just get back the string type?
The exact use case I have is I have many custom classes all of which have a property that is storing another custom class as an optional value. I would like to write a generic function that will create an instance of the object class stored in the optional.
Here is an example of what I am looking for, although .dynamicType does not work since it is an optional:
class Class1 {
}
class Class2 {
var myOp: Class1?
}
var c = Class2()
c.myOp = c.myOp.dynamicType()
Since you wanted to use this with Generics I tried it for you. It works, but it may not be so useful.
First some setup:
This is a helper protocol to make sure our Generic type will have a known init method.
protocol ZeroParameterInit {
init()
}
This is an extension to get the type from an optional:
extension Optional {
var dynamicWrappedType : Wrapped.Type {
return Wrapped.self
}
}
Implemented in your code:
class Class1 : ZeroParameterInit {
required init() {}
}
class Class2 {
var myOp: Class1?
}
var c = Class2()
c.myOp = c.myOp.dynamicWrappedType.init()
Generic implementation:
class Class1 : ZeroParameterInit {
required init() {}
}
class Class2<T where T : ZeroParameterInit> {
var attribute: Optional<T>// used long syntax to remind you of : Optional<Wrapped>
init(attr:T) {
attribute = attr
attribute = nil
}
}
The function to create the instance:
func myFunc<T>(instance: Class2<T>) -> T {
return instance.attribute.dynamicWrappedType.init()
}
Some tests:
let alpha = Class1()
let beta = Class2(attr: alpha)
beta.attribute = myFunc(beta)
The issue:
You can't create an instance of Class2 without informing it about the type of it's generic attribute. So you need to pass it some object/type and that complicates things again.
Some extra methods that might improve how it all works:
init() {
}
let delta = Class2<Class1>()
delta.attribute = myFunc(delta)
init(type:T.Type) {
}
let epsilon = Class2(type: Class1.self)
epsilon.attribute = myFunc(epsilon)
You just need to check if the optional exist:
func myFunc(c: Class2) -> Class1? {
if let c1 = c.myOp{
return c1.dynamicType()
}
return nil
}
OR
func myFunc(c: Class2) -> Class1? {
if c.myOp != nil{
return c.myOp!.dynamicType()
}
return nil
}
Note the your return type need to be optional as well.
Tried this in simulator, seems like doing the right thing, if I understood you
class Class1 {
}
class Class2 {
var myOp: Class1?
}
func myFunc(c: Class2) -> AnyObject {
if let c1 = c.myOp{
return c1.self
}
return c
}
var object = Class2()
object.myOp = Class1()
myFunc(object) // Class1

What is the correct way to create preset Structs?

In Swift classes we can use a class function to create preset instances. Like the calendar example below:
let calender = NSCalendar.currentCalendar()
Which will have a similar pattern as this :
class SomeClass {
var attribute : String
init(value:String) {
attribute = value
}
class func testClass() -> SomeClass {
return SomeClass(value: "test")
}
}
let test = SomeClass.testClass()
But there are no class functions in structs obviously. Xcode recommends using static instead. This is very close to the singleton pattern.
struct SomeStruct {
var attribute : String
init(value:String) {
attribute = value
}
static var testStruct = SomeStruct(value: "test")
}
Singleton pattern
class Singleton {
static let shared = Singleton()
private init() {
}
}
So is this an ok way to init a struct with preset values since structs are value types. If it is not ok, what is the correct way?
The equivalent of class func for struct types is static func:
static func testStruct() -> SomeStruct {
return SomeStruct(value: "foo")
}
and a static property (the "singleton-pattern") works identically
with both class and struct types:
static let singleStruct = SomeStruct(value: "foo")
testStruct() creates a value on each call, whereas singleStruct
creates the value once (on the first call).
In most cases that would make no difference because structures are
value types. The static property has advantages if creating the
value is "expensive". Also, as #Lance noticed in a comment,
this pattern is used by Apple frequently, such as CGRect.zero.
However, it makes a difference if the struct has properties which
are reference types (or pointers to unmanaged memory). Here is an example:
class MyClass {
var attribute : String
init(value : String) {
attribute = value
}
}
struct SomeStruct {
var ptr : MyClass
init(value : String) {
ptr = MyClass(value: value)
}
static func testStruct() -> SomeStruct {
return SomeStruct(value: "foo")
}
static let singleStruct = SomeStruct(value: "foo")
}
Using the static function:
let test1 = SomeStruct.testStruct()
print(test1.ptr.attribute) // foo
let test2 = SomeStruct.testStruct()
test2.ptr.attribute = "bar"
print(test1.ptr.attribute) // foo
Here test1 and test2 are separate values and we get the expected
output.
Using the static property:
let test1 = SomeStruct.singleStruct
print(test1.ptr.attribute) // foo
let test2 = SomeStruct.singleStruct
test2.ptr.attribute = "bar"
print(test1.ptr.attribute) // bar <--- What?
Here, test1 and test2 are set to the same value returned from
the static property. Changing test2.ptr does not mutate test2,
resulting in the somewhat unexpected output for test1.ptr.attribute
See Friday Q&A 2015-04-17: Let's Build Swift.Array for an interesting article on how this can be solved.
Btw, static can be used with class types as well, here static
is a shortcut for class final: a type method that cannot be overridden
in a subclass. Since there is no inheritance for struct types it makes
sense that type methods for struct types are written as static.

XXXX!.Type does not have a memeber YYYY

class SomeClass {
class var category: Int {
return 1class SomeClass {
class var category: Int {
return 1
}
}
class AnotherClass {
var someClass: SomeClass!
init() {
someClass = SomeClass()
}
}
var a = AnotherClass()
println("\(a.someClass.dynamicType.category)") // error: SomeClass!.Type does not have a member named category
println("\(SomeClass.category)") // print 1
of course I can use SomeClass.category,
here is just an example to show the problem.
when I don't know the exact type of a.someClass, inheritance for example, how can I do it?
You can:
println("\(a.someClass!.dynamicType.category)")
Unlike normal member access, .dynamicType does not implicitly unwrap the ImplicitlyUnwrappedOptional
In your case, a.someClass is ImplicitlyUnwrappedOptional<SomeClass>, and ImplicitlyUnwrappedOptional<T> has no .category static member.
So, you have to manually unwrap it with a.someClass!