I'm just starting to take up programming and am trying to understand the way a subclass could update a variable in a superclass. I have a family superclass that keeps track of family members and every time a member of the family is created the family members variable adds 1 to it. here is what i have.
I have tried a couple ways of doing this, including creating a update family members method in the superclass and calling it from the child classes in their init statements but it still didn't work. If anyone could help me or at least explain why its not updating I would be grateful. Thanks.
Oh, the playground states it runs the familymembers++ 4 times, but the variable is not keeping the updates. I have also tried creating two variable and having one update the other but still nothing.
EDIT:
Thank you. I will try and understand the concept better. I appreciate your help. Thanks :D
class Family {
var familyMembers = 0
init() {
familyMembers++
}
func talk() {
println("The family is talking")
}
func argue() {
println("The family is arguing")
}
}
class Son : Family {
var hisName = ""
init(name: String) {
super.init()
self.hisName = name
}
override func argue() {
println("\(hisName) is arguing")
}
}
class Mother : Family {
var herName = ""
init(name: String) {
super.init()
self.herName = name
}
}
let barthelemy = Family()
let ayden = Son(name: "ayden")
let tasha = Mother(name: "tasha")
let jim = Son(name: "jim")
barthelemy.familyMembers
This is because each time you create a Family object or a subclass (so a Son or Mother), you're referencing a different Family: familyMembers++ gets called, but it's for the variable for each specific family member rather than a shared variable that is accessed by each object.
It seems like you're a little confused about what a subclass (and, by extension, inheritance) symbolizes: instead of thinking that a subclass belongs to its parent class, pretend that a subclass is a more specific version of its parent class. For example, a Jaguar would be a subclass of an Animal; a Sedan would be a subclass of a Car; to use your example, a Son would not be a subclass of a Family, but a subclass of a FamilyMember.
Consider the following example, in which we pass a common Family object to the FamilyMember constructor to keep track of the number of members:
import Cocoa
class Family {
var familyMembers = 0
func talk() {
println("The family is talking")
}
func argue() {
println("The family is arguing")
}
}
class FamilyMember {
init(family: Family) {
family.familyMembers++
}
}
class Son : FamilyMember {
var hisName = ""
init(family: Family, name: String) {
super.init(family: family)
self.hisName = name
}
}
class Mother : FamilyMember {
var herName = ""
init(family: Family, name: String) {
super.init(family: family)
self.herName = name
}
}
let barthelemy = Family()
let ayden = Son(family: barthelemy, name: "ayden")
let tasha = Mother(family: barthelemy, name: "tasha")
let jim = Son(family: barthelemy, name: "jim")
barthelemy.familyMembers // returns '3'
Related
The TornadoFX docs describe using the ListCellFragment to bind each cell in a list control to each item model in a list. I am wondering how to do something similar in a flowpane. I'd like to use that kind of class to render a bunch of controls and an SVG drawing in each cell. (So it would replace the button component in the example code below and somehow bind the shapeItem model to it).
class LibraryView : View("Current Library") {
val shapeLibraryViewModel : LibraryViewModel by inject()
override val root = anchorpane{
flowpane {
bindChildren(shapeLibraryViewModel.libraryItemsProperty){
shapeItem -> button(shapeItem.nameProperty)
}
}
}
}
Since I don't see a pre-made class like the one for list view, perhaps I would need to create something similar to it...or maybe there's a more lightweight approach?
Using an ItemFragment is a bit overkill, since the itemProperty of the fragment will never change (a new fragment would be created for every item whenever the libraryItemsProperty change. However, if your view logic for each item is substantial, this approach will provide a clean way to separate and contain that logic, so it might be worth it. Here is a complete example you can use as a starting point.
class ShapeItemFragment : ItemFragment<ShapeItem>() {
val shapeModel = ShapeItemModel().bindTo(this)
override val root = stackpane {
label(shapeModel.name)
}
}
class ShapeItem(name: String) {
val nameProperty = SimpleStringProperty(name)
}
class ShapeItemModel : ItemViewModel<ShapeItem>() {
val name = bind(ShapeItem::nameProperty)
}
class LibraryViewModel : ViewModel() {
val libraryItemsProperty = SimpleListProperty<ShapeItem>(
listOf(
ShapeItem("Shape 1"),
ShapeItem("Shape 2")
).observable()
)
}
class LibraryView : View("Current Library") {
val shapeLibraryViewModel: LibraryViewModel by inject()
override val root = anchorpane {
flowpane {
bindChildren(shapeLibraryViewModel.libraryItemsProperty) { shapeItem ->
val itemFragment = find<ShapeItemFragment>()
itemFragment.itemProperty.value = shapeItem
itemFragment.root
}
}
}
}
A slightly lighter version would be to pass the parameter into your fragment manually and just extend Fragment:
class ShapeItemFragment : Fragment() {
val item: ShapeItem by param()
override val root = stackpane {
label(item.nameProperty)
}
}
You can still bind to changes to properties inside the ShapeItem, since the underlying item won't change (as seen from the ItemFragment) anyway.
Your bindChildren statement would then look like this:
bindChildren(shapeLibraryViewModel.libraryItemsProperty) { shapeItem ->
find<ShapeItemFragment>(ShapeItemFragment::item to shapeItem).root
}
Currently I'm working on my new App written with Swift 2.0. Today I faced two strange errors in Xcode beta 5. I'd love if someone with a previous beta version of Xcode can confirm if I'm right or not. I also could misunderstand something, so I'll appreciate any feedback.
Here is some example code that made me struggle a while:
// Frist bug
protocol SomeProtocol {
var someArray: [String] { get set } // #1 bug
}
extension SomeProtocol {
func someFunction(someString: String) {
self.someArray.append(someString) // #1: Immutable value of type '[String]' only has mutating members named 'append'
}
}
// Second bug
protocol SomeInterfaceProtocol {
var someBool: Bool { get set } // #2 bug
}
class SomeClass: SomeInterfaceProtocol {
var someBool: Bool = false
func returnInterface() -> SomeInterfaceProtocol {
return self
}
}
let someInstance = SomeClass()
// can't set the value
someInstance.returnInterface().someBool = true // #2: Cannot assign to property: function call returns immutable value
The first error can be solved if you add the modifier mutating before the extension func declaration like this:
mutating func someFunction(someString: String) {
I suspect that's a change in the language.
The other one puzzles me as well. At least, here's a work-around:
var c = someInstance.returnInterface()
c.someBool = true
I think the second one isn't a bug as well for the same reason that you can't modify an item in a dictionary directly, or that you can't change elem in for elem in array { ... }.
Something has to be saved to be able to change it. Because you're returning the protocol type, the compiler can't know whether it's a struct or a class, whereas if it's a struct the operation of changing it would have no effect because it's not persisted in any way and structs aren't passed by reference. That's why Thomas' workaround works. Maybe it'll work too if returnInterface returned a class instance, instead of the protocol type.
EDIT: Just tried it out: Indeed it works either if you return SomeClass instead of SomeInterfaceProtocol or if you change the protocol to a class protocol, as it can't be a struct
protocol SomeInterfaceProtocol : class {
var someBool: Bool { get set }
}
class SomeClass: SomeInterfaceProtocol {
var someBool: Bool = false
func returnInterface() -> SomeInterfaceProtocol {
return self
}
}
or
protocol SomeInterfaceProtocol {
var someBool: Bool { get set }
}
class SomeClass: SomeInterfaceProtocol {
var someBool: Bool = false
func returnInterface() -> SomeClass {
return self
}
}
both work
I am subclassing NSObject in order to have an ordered collection that is accessible to Cocoa Bindings. My class looks more or less like this:
public class OrderedCollection<Tk: Hashable, Tv> : NSObject {
var keys: Array<Tk> = []
var values: Dictionary<Tk,Tv> = [:]
override init() {
super.init()
}
// Subscript methods go here
override public var description: String {
var result = "{\n"
for i in 0..<self.count {
result += "[\(i)]: \(self.keys[i]) => \(self[i]!)\n"
}
result += "}"
return result
}
}
It doesn't compile. The error says: '#objc' getter for non-'#objc' property.
Is there a way of making the getter non-'#objc' as it were? I don't need the property to be accessible from Objective-C...
It seems the answer was in the comments of an entirely different question. https://stackoverflow.com/a/26688572/4180258
Essentially, there is a bit of an ugly workaround:
class BaseNSObjectWithDescriptionFix: NSObject {
func makeDescription() -> String {
return super.description
}
override var description: String {
return makeDescription()
}
}
Now you just use BaseNSObjectWithDescriptionFix instead of NSObject and override makeDescription as you like.
In my case, I didn't need it because for my purposes I could use [String] and [String:AnyObject], but this may be of some use to someone in the future.
To override the description property of NSObject when subclassing in Swift, with two generic types like you have and keeping your class public, you just need this:
public class OrderedCollection<Tk: Hashable, Tv>: NSObject {
override public var description: String {
return "hello"
}
}
You could also, instead, conform to the CustomStringConvertible protocol (formerly, pre-Swift 2, known as Printable) and forget NSObject, like so:
public class OrderedCollection<Tk: Hashable, Tv>: CustomStringConvertible {
public var description: String {
return "hello"
}
}
In other words, generics don't really change anything for this case. (Not sure if things were different in an earlier version of Swift...)
The content of description I leave to you (e.g. you don't have a count property above, so I'm guessing you omitted more code than just subscript methods).
I'm trying to write a generic class in Swift who's generic type both inherits from a class and conforms to a protocol. However, the following code results in a compiler crash with Segmentation fault: 11.
protocol Protocol {
var protocolProperty: Any? { get }
}
class Class {
var classProperty: Any?
}
class GenericClass<T: Class where T: Protocol> {
var genericProperty: T?
func foo() {
let classProperty: Any? = genericProperty!.classProperty
// This is the culprit
let protocolProperty: Any? = genericProperty!.protocolProperty
}
}
Commenting out the access to the protocol property allows the program to compile. There is no way to access anything from the protocol without the compiler crashing. Is there a workaround to creating a generic class that works like this?
As MikeS notes, you should open a radar for the crash. It should never crash.
But the solution is to focus on what protocol (i.e. list of methods) you actually need T to conform to rather than getting wrapped up in the class. For instance:
protocol WhatGenericClassHolds : Protocol {
var classProperty: Any? { get }
}
class GenericClass<T: WhatGenericClassHolds> { ... }
There is a problem in your declaration. conform your class to the protocol as below
protocol A {
var somePropertyInt : Int? {get }
}
class B:A {
var someProperty : String?
var somePropertyInt:Int?;
}
class GenericClass<T: B where T: A > {
var someGenericProperty : T?
func foo() {
println(someGenericProperty!.someProperty)
println(someGenericProperty!.somePropertyInt)
}
}
var someGen = GenericClass()
someGen.someGenericProperty?.somePropertyInt
someGen.someGenericProperty?.someProperty
I have the following class that inherits from NSManagedObject:
import Foundation
import CoreData
class Note: NSManagedObject {
#NSManaged var text: String
#NSManaged var name: String
init(name: String, text:String, context: NSManagedObjectContext){
let entity = NSEntityDescription.entityForName("Note", inManagedObjectContext: context);
super.init(entity: entity!, insertIntoManagedObjectContext: context)
self.text = text
self.name = name;
}
}
When I create instances of it, everything works fine, but when I make a search for these entities, I get a very odd error:
fatal error: use of unimplemented initializer 'init(entity:insertIntoManagedObjectContext:)'
This is the code that causes the error:
func coreDatePlayground(){
var note = Note(name: "A new note", text: "blah", context: self.managedObjectContext!)
println("\(note.name) \(note.text)")
var noote2 = Note(name: "Another note", text: "blah blah", context: self.managedObjectContext!)
managedObjectContext?.save(nil)
var fetch = NSFetchRequest(entityName: "Note")
// This line causes the crash.
var results = self.managedObjectContext?.executeFetchRequest(fetch, error: nil)
if let objects = results{
println(objects.count)
}
}
I found out that changing the initialiser by making it a convenience one and calling on self instead of on super gets rid of the issue, but I have no idea why.
convenience init(name: String, text:String, context: NSManagedObjectContext){
let entity = NSEntityDescription.entityForName("Note", inManagedObjectContext: context);
self.init(entity: entity!, insertIntoManagedObjectContext: context)
self.text = text
self.name = name;
}
The code above works, but I have no idea why. Anybody knows what's going on? Is it a bug or is my fault?
This is documented behavior.
Swift subclasses do not inherit their superclass initializers by default
For example, following code does not even compile, because Child does not inherit init(id:String) automatically. This mechanism make sure name in Child class properly initialized.
class Parent {
var id:String
init(id:String) {
self.id = id
}
}
class Child:Parent {
var name:String
init(id:String, name:String) {
self.name = name
super.init(id: id)
}
}
var child1 = Child(id:"child1")
If you define only convenience initializers in subclass, then it automatically inherits all of its superclass designated initializers as documented in "Automatic Initializer Inheritance" section
You must implement the following in your NSManagedObject subclass (this is the Swift 3.0 version):
#objc
private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
super.init(entity: entity, insertInto: context)
}
The answer is kind of answering it, but not really directly.
The reasoning for this is that Swift does not inherit their supercalls designated initializers by default AND it seems as CoreData by uses this initializer when doing fetches (insert a breakpoint in the method to see). So here we "bring up" the designated initializer for CoreData to use.
If you have NSManagedObject base classes, you must also implement this method in those.
Credits to JSQCoreDataKit for the idea.