How do I override this class property? [duplicate] - ios

This question already has answers here:
Overriding a stored property in Swift
(14 answers)
Closed 5 years ago.
struct SectionData {
var items : [LiveCellObjectProtocol]
var title: String? = nil
subscript(index: Int) -> LiveCellObjectProtocol {
return items[index]
}
}
extension SectionData{
init(title: String? = nil){
self.title = title
self.items = []
}
}
class LiveCellTableViewController: UIViewController {
var sections: [SectionData] = {
return [SectionData(title: "aaa"), SectionData(title: "bbb"), SectionData(title: "ccc")]
}()
}
How do I override sections if I subclass this? I'd like to change the titles.
This doesn't build.
class SomeChild: LiveCellTableViewController {
override var sections: [SectionData] = {
return [SectionData(title: nil), SectionData(title: "Mutual"), SectionData(title: "Connections")]
}()
}

An override property cannot be a stored property. That's just the way Swift works (and this makes sense if you think about it). I list the possibilities in my book as follows:
If the superclass property is writable (a stored property or a computed property with a setter), the subclass’s override may consist
of adding setter observers to this property.
Alternatively, the subclass’s override may be a computed property. In that case:
If the superclass property is stored, the subclass’s computed
property override must have both a getter and a setter.
If the superclass property is computed, the subclass’s computed
property override must reimplement all the accessors that the
superclass implements. If the superclass property is read-only (it has
just a getter), the override can add a setter.
So the way to do what you want to do here is to override, not the property, but the class's initializer. Here's a highly simplified example:
class C {
var sections : [Int] = [1,2,3]
}
class CC : C {
override init() {
super.init()
super.sections = [4,5,6]
}
}
C().sections // [1,2,3]
CC().sections // [4,5,6]

You can't override a stored property in swift. You can use private storage and calculated properties to work around the issue. Something like this:
//: Playground - noun: a place where people can play
import Cocoa
struct SectionData {
let title: String
}
class ParentClass {
private let defaultSections = [SectionData(title: "Parent")]
var sections: [SectionData] {
return defaultSections
}
}
class ChildClass: ParentClass {
private let childSections = [SectionData(title: "Child")]
override var sections: [SectionData] {
return childSections
}
}
// If you wanted a child who appends sections
class AnotherChildClass: ParentClass {
private let childSections = [SectionData(title: "Child")]
override var sections: [SectionData] {
return super.sections + childSections
}
}
Also, because in your example you're just overriding the parent class functionality and your property is immutable, you could just make it a parameter passed in during init.
//: Playground - noun: a place where people can play
import Cocoa
struct SectionData {
let title: String
}
class ParentClass {
let sections: [SectionData]
init(sections: [SectionData]) {
self.sections = sections
}
}
class ChildClass: ParentClass {
}
let parent = ParentClass(sections: [SectionData(title: "Parent")])
let child = ChildClass(sections: [SectionData(title: "Child")])

Get rid of the equals signs:
var sections: [SectionData] {
return [SectionData(title: "aaa"), SectionData(title: "bbb"), SectionData(title: "ccc")]
}
That's why Xcode wanted parentheses. With the equals sign, your code block was defining an inline function, and the () calls the function, using the result to initialize your variable. Without the () you're trying to assign a function to an array.
Without the =, you're defining a property with a getter, which (I assume) is what you want.

Just change the value in your subclass after you create it, if you're loading it from a storyboard, the easiest place is in awakeFromNib:
class SomeChild: LiveCellTableViewController {
override func awakeFromNib() {
super.awakeFromNib()
sections = [SectionData(title: nil), SectionData(title: "Mutual"), SectionData(title: "Connections")]
}
}

Related

DidSet not working in init function swift 3

I have already seen
Is it possible to allow didSet to be called during initialization in Swift?
for me it is not working..
I am working in project where I have created class below
protocol FileManagerHelper {
var fileName:String {get}
var fileCategory:FileCategory {get set}
var isFileExitsAtPath:Bool {get}
var filePath:String {get}
var fileType:FileTypes {get set}
}
class FileManager:FileManagerHelper {
// Other property
//STORED PROPERY INIT WHEN OBJECT WILL CREATED WITH FileCategory OBJECT
var fileCategory:FileCategory {
didSet {
switch fileCategory {
case .XYZ:
print("Test")
... other cases
}
}
required init(fileCategory:FileCategory,fileType:FileTypes = .Image) {
self.fileCategory = fileCategory
self.path = self.folderPath + self.fileName
}
}
did set method is not calling of fileCategory
NOTE: I don't want to give default value , I want to pass it runtime from init method
Tries
1) defer
use of self in method called $defer before all stored property are initialised
2) Create custom method that will assign that value and call it from init
private func setCategory(with category:FileCategory) {
self.fileCategory = category
}
Use of method call setCategory before stored property ...
I know that all stored property should be initialised before instance created. Till that instance will not been created so i won't call methods (using self) may be that why above solution not working
Please help me if any one have idea
For me, using the defer is better readable.
import Foundation
class A {
var b: String {
didSet {
print("didSet called with value: \(b)")
}
}
init(x: String) {
self.b = x
defer { self.b = x }
}
}
let a = A(x: "It's Working!") // didSet called with value: It's Working!
print(a.b) // It's Working
One way to solve this is to extract the didSet logic into a separate method and call this method from both didSet and init:
class FileManager: FileManagerHelper {
var fileCategory:FileCategory {
didSet {
didSetFileCategory()
}
}
required init(fileCategory:FileCategory,fileType:FileTypes = .Image) {
self.fileCategory = fileCategory
self.path = self.folderPath + self.fileName
didSetFileCategory()
}
private func didSetFileCategory() {
switch fileCategory {
case .XYZ:
print("Test")
//... other cases
}
}
}

Overriding properties in swift

For example a have a first class
public class MyBaseButton: UIButton {
public var weight: Double = 1.0
public var text: String? {
get {
return self.titleForState(.Normal)
}
set {
return self.setTitle(newValue, forState: .Normal)
}
}
}
And inherited class:
public class SomeButton: SomeBaseButton {
override public var text: String? = "text"
override public var weight: Double = 2.0
}
So, the logic is that SomeClass define own text and weight.
But I'm getting an errors:
For text: "Cannot override with a stored property 'text'"
For weight: "Cannot override with a stored property 'weight'"
Interestingly this works just fine in pure Swift classes. For example, this works as expected:
public class FooButton {
public var weight: Double = 1.0
}
public class BarButton: FooButton {
override public var weight: Double = 2.0
}
The reason it does not work for you is because you are working with Objective-C classes: since UIButton is an Objective-C class, all its subclasses will be too. Because of that, the rules seem to be a bit different.
Xcode 6.3 is actually a bit more informative. It shows the following two errors:
Getter for "weight" overrides Objective-C method "weight" from superclass "FooButton"
Setter for "weight" overrides Objective-C method "setWeight:" from superclass "Foobutton"
Since the following does work ...
public class BarButton: FooButton {
override public var weight: Double {
get {
return 2.0
}
set {
// Do Nothing
}
}
}
... my guess is that these methods are simply not synthesized correctly.
I wonder if this is a compiler bug. Or a shortcoming. Because I think it could handle the case.
Maybe the Swift designers thought that in case of overriding weight you could also simply set it to a different value in your initializer. Hm.
In addition, if someone wants to override property to have dynamic effect, see KVO
class MyClass: NSObject {
var date = NSDate()
}
class MyChildClass: MyClass {
dynamic override var date: NSDate {
get { return super.date }
set { super.date = newValue }
}
}
In the above you have a getter and a setter.
When you override it, you are just assigning it a value.
Instead set up the setter and getter as you have above.
var _text:Text
override public var text: String? {
get {
return _text
}
set {
_text = newValue
}
}
I ran into this issue when trying to override the NSPredicateRowEditor templateViews property in Swift 3.
Superclass property to override:
open var templateViews: [NSView] { get }
Override like so:
class CustomRowTemplate: NSPredicateEditorRowTemplate {
override var templateViews: [NSView] {
get {
let templateViews = super.templateViews
// custom subclass work goes here
return templateViews
}
//set {
// Superclass property is `get` only, other properties might need a setter
//}
}
}

Swift - dynamicType in initializer of Subclass returns BaseClass instead

I'm trying to create a Abstract class that can fetch records from CloudKit and return the appropriate instances based on the subclass that called the fetch method.
The problem is the class method of the Base class doesn't return an instance of the Subclass.
Run the following code in playgrounds:
class Base {
class var value: String { return "Base" }
class func doSomething() -> Self { // In Obj-C this would return instanceType
println("doSomething() = \(self.value)")
let object = self.init()
return object
}
init() {
println("init() = \(self.dynamicType.value)")
}
}
class Sub: Base {
override class var value: String { return "Sub" }
override init() {
super.init()
println("Value = \(self.dynamicType.value)")
}
}
println("Base")
let base = Base.doSomething() // type = Base
println()
println("Sub")
let sub = Sub.doSomething() // type = Base !!
For some reason when calling doSomething() on the Subclass, the initializer prints the value of the Base class property ("Base" instead of "Sub):
Base doSomething() = Base
init() = Base
Sub doSomething() = Sub
init() = Base
You should get the correct string value when you do a:
NSStringFromClass(self.dynamicType)

Is it possible to allow didSet to be called during initialization in Swift?

Question
Apple's docs specify that:
willSet and didSet observers are not called when a property is first initialized. They are only called when the property’s value is set outside of an initialization context.
Is it possible to force these to be called during initialization?
Why?
Let's say I have this class
class SomeClass {
var someProperty: AnyObject {
didSet {
doStuff()
}
}
init(someProperty: AnyObject) {
self.someProperty = someProperty
doStuff()
}
func doStuff() {
// do stuff now that someProperty is set
}
}
I created the method doStuff, to make the processing calls more concise, but I'd rather just process the property within the didSet function. Is there a way to force this to call during initialization?
Update
I decided to just remove the convenience intializer for my class and force you to set the property after initialization. This allows me to know didSet will always be called. I haven't decided if this is better overall, but it suits my situation well.
If you use defer inside of an initializer, for updating any optional properties or further updating non-optional properties that you've already initialized and after you've called any super.init() methods, then your willSet, didSet, etc. will be called. I find this to be more convenient than implementing separate methods that you have to keep track of calling in the right places.
For example:
public class MyNewType: NSObject {
public var myRequiredField:Int
public var myOptionalField:Float? {
willSet {
if let newValue = newValue {
print("I'm going to change to \(newValue)")
}
}
didSet {
if let myOptionalField = self.myOptionalField {
print("Now I'm \(myOptionalField)")
}
}
}
override public init() {
self.myRequiredField = 1
super.init()
// Non-defered
self.myOptionalField = 6.28
// Defered
defer {
self.myOptionalField = 3.14
}
}
}
Will yield:
I'm going to change to 3.14
Now I'm 3.14
Create an own set-Method and use it within your init-Method:
class SomeClass {
var someProperty: AnyObject! {
didSet {
//do some Stuff
}
}
init(someProperty: AnyObject) {
setSomeProperty(someProperty)
}
func setSomeProperty(newValue:AnyObject) {
self.someProperty = newValue
}
}
By declaring someProperty as type: AnyObject! (an implicitly
unwrapped optional), you allow self to fully initialize without
someProperty being set. When you call
setSomeProperty(someProperty) you're calling an equivalent of
self.setSomeProperty(someProperty). Normally you wouldn't be able to
do this because self hasn't been fully initialized. Since
someProperty doesn't require initialization and you are calling a
method dependent on self, Swift leaves the initialization context and
didSet will run.
As a variation of Oliver's answer, you could wrap the lines in a closure. Eg:
class Classy {
var foo: Int! { didSet { doStuff() } }
init( foo: Int ) {
// closure invokes didSet
({ self.foo = foo })()
}
}
Edit: Brian Westphal's answer is nicer imho. The nice thing about his is that it hints at the intent.
I had the same problem and this works for me
class SomeClass {
var someProperty: AnyObject {
didSet {
doStuff()
}
}
init(someProperty: AnyObject) {
defer { self.someProperty = someProperty }
}
func doStuff() {
// do stuff now that someProperty is set
}
}
This works if you do this in a subclass
class Base {
var someProperty: AnyObject {
didSet {
doStuff()
}
}
required init() {
someProperty = "hello"
}
func doStuff() {
print(someProperty)
}
}
class SomeClass: Base {
required init() {
super.init()
someProperty = "hello"
}
}
let a = Base()
let b = SomeClass()
In a example, didSet is not triggered. But in b example, didSet is triggered, because it is in the subclass. It has to do something with what initialization context really means, in this case the superclass did care about that
While this isn't a solution, an alternative way of going about it would be using a class constructor:
class SomeClass {
var someProperty: AnyObject {
didSet {
// do stuff
}
}
class func createInstance(someProperty: AnyObject) -> SomeClass {
let instance = SomeClass()
instance.someProperty = someProperty
return instance
}
}
In the particular case where you want to invoke willSet or didSet inside init for a property available in your superclass, you can simply assign your super property directly:
override init(frame: CGRect) {
super.init(frame: frame)
// this will call `willSet` and `didSet`
someProperty = super.someProperty
}
Note that Charlesism solution with a closure would always work too in that case. So my solution is just an alternative.
unfortunately, didSet observers aren't called when a root class is initialized.
If your class isn't a subclass, you have to use getters and setters to achieve the functionality you want:
class SomeClass {
private var _test: Int = 0
var test: Int {
get { _test }
set { _test = newValue }
}
init(test: Int) { self.test = test }
}
alternatively, if your class is a subclass, you can use didSet and do:
override init(test: int) {
super.init()
self.test = test
}
The didSet SHOULD get called after super.init() is called.
One thing I have not tried but MIGHT also work:
init(test: int) {
defer { self.test = test }
}
NOTE: you will need to make your properties nullable, or set a default value for them, or unwrap the class properties.
You can solve it in obj-с way:
class SomeClass {
private var _someProperty: AnyObject!
var someProperty: AnyObject{
get{
return _someProperty
}
set{
_someProperty = newValue
doStuff()
}
}
init(someProperty: AnyObject) {
self.someProperty = someProperty
doStuff()
}
func doStuff() {
// do stuff now that someProperty is set
}
}

Custom class clusters in Swift

This is a relatively common design pattern:
https://stackoverflow.com/a/17015041/743957
It allows you to return a subclass from your init calls.
I'm trying to figure out the best method of achieving the same thing using Swift.
I do know that it is very likely that there is a better method of achieving the same thing with Swift. However, my class is going to be initialized by an existing Obj-C library which I don't have control over. So it does need to work this way and be callable from Obj-C.
Any pointers would be very much appreciated.
I don't believe that this pattern can be directly supported in Swift, because initialisers do not return a value as they do in Objective C - so you do not get an opportunity to return an alternate object instance.
You can use a type method as an object factory - a fairly contrived example is -
class Vehicle
{
var wheels: Int? {
get {
return nil
}
}
class func vehicleFactory(wheels:Int) -> Vehicle
{
var retVal:Vehicle
if (wheels == 4) {
retVal=Car()
}
else if (wheels == 18) {
retVal=Truck()
}
else {
retVal=Vehicle()
}
return retVal
}
}
class Car:Vehicle
{
override var wheels: Int {
get {
return 4
}
}
}
class Truck:Vehicle
{
override var wheels: Int {
get {
return 18
}
}
}
main.swift
let c=Vehicle.vehicleFactory(4) // c is a Car
println(c.wheels) // outputs 4
let t=Vehicle.vehicleFactory(18) // t is a truck
println(t.wheels) // outputs 18
The "swifty" way of creating class clusters would actually be to expose a protocol instead of a base class.
Apparently the compiler forbids static functions on protocols or protocol extensions.
Until e.g. https://github.com/apple/swift-evolution/pull/247 (factory initializers) is accepted and implemented, the only way I could find to do this is the following:
import Foundation
protocol Building {
func numberOfFloors() -> Int
}
func createBuilding(numberOfFloors numFloors: Int) -> Building? {
switch numFloors {
case 1...4:
return SmallBuilding(numberOfFloors: numFloors)
case 5...20:
return BigBuilding(numberOfFloors: numFloors)
case 21...200:
return SkyScraper(numberOfFloors: numFloors)
default:
return nil
}
}
private class BaseBuilding: Building {
let numFloors: Int
init(numberOfFloors:Int) {
self.numFloors = numberOfFloors
}
func numberOfFloors() -> Int {
return self.numFloors
}
}
private class SmallBuilding: BaseBuilding {
}
private class BigBuilding: BaseBuilding {
}
private class SkyScraper: BaseBuilding {
}
.
// this sadly does not work as static functions are not allowed on protocols.
//let skyscraper = Building.create(numberOfFloors: 200)
//let bigBuilding = Building.create(numberOfFloors: 15)
//let smallBuilding = Building.create(numberOfFloors: 2)
// Workaround:
let skyscraper = createBuilding(numberOfFloors: 200)
let bigBuilding = createBuilding(numberOfFloors: 15)
let smallBuilding = createBuilding(numberOfFloors: 2)
Since init() doesn't return values like -init does in Objective C, using a factory method seems like the easiest option.
One trick is to mark your initializers as private, like this:
class Person : CustomStringConvertible {
static func person(age: UInt) -> Person {
if age < 18 {
return ChildPerson(age)
}
else {
return AdultPerson(age)
}
}
let age: UInt
var description: String { return "" }
private init(_ age: UInt) {
self.age = age
}
}
extension Person {
class ChildPerson : Person {
let toyCount: UInt
private override init(_ age: UInt) {
self.toyCount = 5
super.init(age)
}
override var description: String {
return "\(self.dynamicType): I'm \(age). I have \(toyCount) toys!"
}
}
class AdultPerson : Person {
let beerCount: UInt
private override init(_ age: UInt) {
self.beerCount = 99
super.init(age)
}
override var description: String {
return "\(self.dynamicType): I'm \(age). I have \(beerCount) beers!"
}
}
}
This results in the following behavior:
Person.person(10) // "ChildPerson: I'm 10. I have 5 toys!"
Person.person(35) // "AdultPerson: I'm 35. I have 99 beers!"
Person(35) // 'Person' cannot be constructed because it has no accessible initializers
Person.ChildPerson(35) // 'Person.ChildPerson' cannot be constructed because it has no accessible initializers
It's not quite as nice as Objective C, since private means all the subclasses need to be implemented in the same source file, and there's that the minor syntax difference Person.person(x) (or Person.create(x) or whatever) instead of simply Person(x), but practically speaking, it works the same.
To be able to instantiate literally as Person(x), you could turn Person into a proxy class which contains a private instance of the actual base class and forwards everything to it. Without message forwarding, this works for simple interfaces with few properties/methods but it gets unwieldy for anything more complex :P
I think actually the Cluster pattern can be implemented in Swift using runtime functions. The main point is to replace the class of your new object with a subclass when initializing. The code below works fine though I think more attention should be paid to subclass' initialization.
class MyClass
{
var name: String?
convenience init(type: Int)
{
self.init()
var subclass: AnyClass?
if type == 1
{
subclass = MySubclass1.self
}
else if type == 2
{
subclass = MySubclass2.self
}
object_setClass(self, subclass)
self.customInit()
}
func customInit()
{
// to be overridden
}
}
class MySubclass1 : MyClass
{
override func customInit()
{
self.name = "instance of MySubclass1"
}
}
class MySubclass2 : MyClass
{
override func customInit()
{
self.name = "instance of MySubclass2"
}
}
let myObject1 = MyClass(type: 1)
let myObject2 = MyClass(type: 2)
println(myObject1.name)
println(myObject2.name)
protocol SomeProtocol {
init(someData: Int)
func doSomething()
}
class SomeClass: SomeProtocol {
var instance: SomeProtocol
init(someData: Int) {
if someData == 0 {
instance = SomeOtherClass()
} else {
instance = SomethingElseClass()
}
}
func doSomething() {
instance.doSomething()
}
}
class SomeOtherClass: SomeProtocol {
func doSomething() {
print("something")
}
}
class SomethingElseClass: SomeProtocol {
func doSomething() {
print("something else")
}
}
Basically you create a protocol that your class cluster inherits from. You then wrap around an instance variable of the same type and choose which implementation to use.
For example, if you were writing an array class that switched between a LinkedList or a raw array then SomeOtherClass and SomethingElseClass might be named LinkedListImplementation or PlainArrayImplementation and you could decide which one to instantiate or switch to based on whatever is more efficient.
There is a way to achieve this. Whether it is good or bad practice is for another discussion.
I have personally used it to allow for extension of a component in plugins without exposing the rest of the code to knowledge of the extensions. This follows the aims of the Factory and AbstractFactory patterns in decoupling code from the details of instantiation and concrete implementation classes.
In the example case the switching is done on a typed constant to which you would add in extensions. This kinda contradicts the above aims a little technically - although not in terms of foreknowledge. But in your case the switch might be anything - the number of wheels for example.
I don’t remember if this approach was available in 2014 - but it is now.
import Foundation
struct InterfaceType {
let impl: Interface.Type
}
class Interface {
let someAttribute: String
convenience init(_ attribute: String, type: InterfaceType = .concrete) {
self.init(impl: type.impl, attribute: attribute)
}
// need to disambiguate here so you aren't calling the above in a loop
init(attribute: String) {
someAttribute = attribute
}
func someMethod() {}
}
protocol _Factory {}
extension Interface: _Factory {}
fileprivate extension _Factory {
// Protocol extension initializer - has the ability to assign to self, unlike class initializers.
init(impl: Interface.Type, attribute: String) {
self = impl.init(attribute: attribute) as! Self;
}
}
Then in a concrete implementation file ...
import Foundation
class Concrete: Interface {
override func someMethod() {
// concrete version of some method
}
}
extension InterfaceType {
static let concrete = InterfaceType(impl: Concrete.self)
}
For this example Concrete is the "factory" supplied default implementation.
I have used this, for example, to abstract the details of how modal dialogs were presented in an app where initially UIAlertController was being used and migrated to a custom presentation. None of the call sites needed changing.
Here is a simplified version that does not determine the implementation class at runtime. You can paste the following into a Playground to verify its operation ...
import Foundation
class Interface {
required init() {}
convenience init(_ discriminator: Int) {
let impl: Interface.Type
switch discriminator {
case 3:
impl = Concrete3.self
case 2:
impl = Concrete2.self
default:
impl = Concrete1.self
}
self.init(impl: impl)
}
func someMethod() {
print(NSStringFromClass(Self.self))
}
}
protocol _Factory {}
extension Interface: _Factory {}
fileprivate extension _Factory {
// Protocol extension initializer - has the ability to assign to self, unlike class initializers.
init(impl: Interface.Type) {
self = impl.init() as! Self;
}
}
class Concrete1: Interface {}
class Concrete2: Interface {}
class Concrete3: Interface {
override func someMethod() {
print("I do what I want")
}
}
Interface(2).someMethod()
Interface(1).someMethod()
Interface(3).someMethod()
Interface(0).someMethod()
Note that Interface must actually be a class - you can't collapse this down to a protocol avoiding the abstract class even if it had no need for member storage. This is because you cant invoke init on a protocol metatype and static member functions cannot be invoked on protocol metatypes. This is too bad as that solution would look a lot cleaner.
We can take advantage of a compiler quirk - self is allowed to be assigned in protocol extensions - https://forums.swift.org/t/assigning-to-self-in-protocol-extensions/4942.
Thus, we can have in place something like this:
/// The sole purpose of this protocol is to allow reassigning `self`
fileprivate protocol ClusterClassProtocol { }
extension ClusterClassProtocol {
init(reassigningSelfTo other: Self) {
self = other
}
}
/// This is the base class, the one that gets circulated in the public space
class ClusterClass: ClusterClassProtocol {
convenience init(_ intVal: Int) {
self.init(reassigningSelfTo: IntChild(intVal))
}
convenience init(_ stringVal: String) {
self.init(reassigningSelfTo: StringChild(stringVal))
}
}
/// Some private subclass part of the same cluster
fileprivate class IntChild: ClusterClass {
init(_ intVal: Int) { }
}
/// Another private subclass, part of the same cluster
fileprivate class StringChild: ClusterClass {
init(_ stringVal: String) { }
}
Now, let's give this a try:
print(ClusterClass(10)) // IntChild
print(ClusterClass("abc")) // StringChild
This works the same as in Objective-C, where some classes (e.g. NSString, NSArray, NSDictionary) return different subclasses based on the values given at initialization time.

Resources