These are my classes:
class Shape: NSObject {
var prop1:String?
let prop2:String = "Shape Default"
func printEverything(){
var reflection = reflect(self)
for var i = 0 ; i < reflection.count ; i++ {
var (prop,mirror) = reflection[i]
println(prop);
}
}
}
class Rect: Shape {
var prop3:String?
let prop4:String = "Rect Default"
func func2(){
// body2
}
}
var aRect = Rect()
aRect.printEverything()
However printEverything only showed: super, prop3, prop4.
I was expecting to get the whole inheritance, namely: super, prop1, prop2, prop3, prop4, printEverything, func2.
Also, how can I set these property from the reflection?
Thanks
You can only get the properties. If you also want the properties of the base class, then you could try using EVRevlection. See its reflectedSub method for how you could get the properties of the base class. It's in the item with the key super
Related
Let me first excuse for probably missing something basic (and the right expression)
I have a struct where I store several values for a board game. It looks like this and includes about 20 values.
struct Werte {
static var geld: [Int] = [] {didSet {NotificationCenter.default.post(name: .ResourcenAnzeigen, object: nil, userInfo: ["which" : 0])}}
static var erz: [Int] = [] {didSet {NotificationCenter.default.post(name: .ResourcenAnzeigen, object: nil, userInfo: ["which" : 1])}}
static var temperatur = Int() {didSet {NotificationCenter.default.post(name: .TemperaturAnzeigen, object: nil)}}
}
There are several classes like this:
class KarteBlauVerbraucheErhalte {
let use: //what should I declare
let useHowMuch: Int
init(use: /*what should I declare*/ , useHowMuch: Int) {
self.use = use
self.useHowMuch = useHowMuch
}
override func Aktion() {
use += useHowMuch
}
If I declare use with Int and use init(use: Geld[0] , useHowMuch: 99) the code works - but only the class variable use increased by 99.
Geld[0] doesnt change.
How can I make Geld[0] change?
One way is this:
var use: Int {
get {
return Werte.geld[0]
}
set {
// You have access to the newValue by property name 'newValue'.
// Use it. E.g.:
Werte.geld[0] += newValue
}
}
Omit it in the constructor, as it wouldn't make sense and I do not think it compiles.
Background of why your code doesn't work: you are referring to geld[0], which is just an Int. It just passes the actual value, not a reference. But that is a whole other topic.
I'm trying to pass different classes, with the same properties, to the same function. How do I cast them for use with this function?
Below is a simple example to highlight what I'm trying to achieve.
class A {
var height:Int = 10
}
class B {
var height:Int = 20
}
class C {
static func grow(class:AnyObject) {
class.height + 5
}
}
C.grow(A)
C.grow(B)
The two final calls should yield 15 and 25, but without casting the AnyObject back to A or B, an error like the following is generated: "AnyObject has no member named".
How do I accomplish something like this?
Swift reflection API enables you to read values but not modify them. So if that's enough for you, you may use a method similar to the following which takes an object and the label of the member you want to access:
func getValue<T>(object: AnyObject, memberLabel: String) -> T? {
let mirror = Mirror(reflecting: object)
for member in mirror.children {
if let _ = member.label where member.label == memberLabel,
let value = member.value as? T {
return value
}
}
return nil
}
But if you want to modify the values, you have to define a protocol and make the classes conform to it:
protocol HasHeight {
var height: Int { get set }
}
extension HasHeight {
mutating func grow() {
self.height += 5
}
}
class A : HasHeight {
var height = 10
}
class B : HasHeight {
var height = 20
}
var a = A()
print(a.height)
a.grow()
print(a.height)
var b = B()
print(b.height)
b.grow()
print(b.height)
Here I defined grow() as a protocol extension so that it is available on every class/struct that conforms to the HasHeight protocol.
The results are:
10
15
20
25
You may define it elsewhere, but the call will have to be changed to include an & reference:
func grow<T: HasHeight>(inout sized: T) {
sized.height += 5
}
grow(&b)
Looks like a good case for a protocol! Define one with a height property, have A and B both implement that protocol, and then have the grow method accept the protocol as its parameter.
I am learning KVC and binding. Currently, I am trying to bind an NSTextField to a computed property colorWallStr. I have bound the sliders' value to the corresponding color variable and also bound the value of the label to the computed property.
However, the content of the label does not change when I move the slide.
// Inside MainWindowController
dynamic var colorRed: CGFloat = 1.0
dynamic var colorGreen: CGFloat = 1.0
dynamic var colorBlue: CGFloat = 0.0
dynamic var colorWallStr: String {
get {
return "R: \(colorRed) G: \(colorGreen) B: \(colorBlue)"
}
}
It is working fine when I bond the label to the color variable directly.
Thanks #vadian's answer. Now I can update the label using property's didSet to trigger update label method (see below).
dynamic var colorBlue: CGFloat = 0.0 {
didSet {
updateLabel()
}
}
func updateLabel() {
colorWall = "R: \(colorRed) G: \(colorGreen) B: \(colorBlue)"
}
If properties used in string interpolation don't update the enclosing computed property, then why does the following code snippet does not work?
dynamic var colorWall: String {
get {
let red = colorRed
let green = colorGreen
let blue = colorBlue
return "R: \(red) G: \(green) B: \(blue)"
}
}
The Key-Value Observering API lets you handle situations like this by allowing you to register dependent keys. Here's how the documentation introduces the subject:
There are many situations in which the value of one property depends on that of one or more other attributes in another object. If the value of one attribute changes, then the value of the derived property should also be flagged for change.
In this situation the value of colorWallString depends on the value of your three color variables, so all you need to do is implement a class method that makes this clear:
// It's crucial that you get the signature of this method correct,
// otherwise it'll just be ignored.
class func keyPathsForValuesAffectingColorWallStr() -> Set<NSObject> {
return Set<NSObject>(arrayLiteral: "colorRed", "colorBlue", "colorGreen")
}
As noted in the code snippet, the format of the method you use to flag up dependent keys is crucial; you can (and should) read the relevant documentation here.
Properties used in string interpolation don't update the enclosing computed property.
You could do it this way
dynamic var colorRed: CGFloat = 1.0 { didSet { updateLabel() } }
dynamic var colorGreen: CGFloat = 1.0 { didSet { updateLabel() } }
dynamic var colorBlue: CGFloat = 0.0 { didSet { updateLabel() } }
dynamic var colorWallStr = ""
func updateLabel()
{
colorWallStr = String(format:"R: %.2f G: %.2f B: %.2f ", colorRed, colorGreen, colorBlue)
}
For Xcode 9.0, Swift 4:
class SampleViewController: NSViewController {
#objc dynamic var colorRed: CGFloat = 1.0
#objc dynamic var colorGreen: CGFloat = 1.0
#objc dynamic var colorBlue: CGFloat = 0.0
#objc dynamic var colorWallStr: String {
get {
return "R: \(colorRed) G: \(colorGreen) B: \(colorBlue)"
}
}
override class func keyPathsForValuesAffectingValue(forKey key: String) -> Set<String> {
switch key {
case "colorWallStr" :
return Set(["colorRed", "colorGreen", "colorBlue"])
default :
return super.keyPathsForValuesAffectingValue(forKey: key)
}
}
}
Small tips:
Use NSViewController, instead of NSWindowController, in this case.
Further information:
keyPathsForValuesAffecting with NSManagedObject
“In some cases a value may be dependent on another. For example, if you have a Person class with a computed property fullName that is dependent on the properties firstName and lastName, wouldn’t it be nice if observers of fullName could be notified when either firstName or lastName changes? KVO’s designers thought so, too, which is why they implemented a convention for defining dependent keys.
To define a key’s dependencies you must implement a specially named class method which returns a Set of key paths. In the example above you would implement keyPathsForValuesAffectingFullName():”
Excerpt From: Hillegass, Aaron. “Cocoa Programming for OS X: The Big Nerd Ranch Guide, 5/e (Big Nerd Ranch Guides).” iBooks.
I have been updating my game recently to use more value types. I am still not 100% confident with weak and unowned in some cases so I went the struct way to avoid strong reference cycles. As per apples newer keynotes it seems value types are they way to go for the most part anyway.
I have never seen an example where structs are used to render sprites in a spriteKit game so I wonder what the drawbacks are.
I understand that they are copied and not referenced but for my usage it seems to work.
So basically is there something I need to watch out for when doing this
struct Flag {
let post: SKSpriteNode
let flag: SKSpriteNode
init(postImage: String, flagImage: String) {
post = SKSpriteNode(imageNamed: postImage)
// other set ups for post sprite
flag = SKSpriteNode(imageNamed: flagImage)
// other set ups for flag sprite
post.addChild(flag)
}
func animate() {
// code to animate flag
}
}
Than in my SKScenes I simply add them as usual
let flag = Flag(postImage: "FlagPostImage", flagImage: "FlagImage")
flag.post.position = ...
addChild(flag.post)
flag.animate()
Now even if I create multiple flags in the same scene I seem to have no problems with this way.
I am just curious because I have never really seen an example like this so I wonder if I am missing something, like performance drawbacks etc.
Thanks for any help.
Personally I avoid creating Structs that contain Classes. Because Structs copy, each and every copy that get's passed around your app will increase the reference count of the Classes. This makes it harder to manage them instead of easier.
It is also useful to take a look at how UIKit uses Structs. A UIView is an object but has many defining properties that are Structs. For example it's frame.
Drop the code below in a playground to see some effects of this behaviour.
The protocol is just to get some meaningful feedback form the playground.
protocol IDLookable : CustomPlaygroundQuickLookable {
var id : Int { get set }
}
extension IDLookable {
func customPlaygroundQuickLook() -> PlaygroundQuickLook {
return PlaygroundQuickLook.AttributedString(NSAttributedString(string: "\(self.dynamicType) with id : \(self.id)"))
}
}
class MyClass : IDLookable {
var id : Int = 0
init(id : Int) {
self.id = id
}
}
struct MyContainerStruct : IDLookable {
var id : Int = 0
var object : MyClass
init(id : Int, object:MyClass) {
self.id = id
self.object = object
}
}
class Scope {
// ref count = 1
var object = MyClass(id: 11)
var structContainer : MyContainerStruct
init() {
// ref count = 2
structContainer = MyContainerStruct(id: 222, object: object)
messWithAClassInAStruct()
}
func messWithAClassInAStruct() {
// ref count = 3
var structContainerTwo = structContainer
structContainerTwo.id = 333
structContainerTwo.object // 11
// altering the object in one struct will obvously update all references
structContainerTwo.object.id = 1
structContainer.object // 1
structContainerTwo.object // 1
}
}
let test = Scope()
One pattern that does make it easy to work with Reference Types in Value Types is to store them as weak optionals in the Value Types. This means that something will need to have a strong reference but chances are that some Class will be responsible for creating the Structs this is a good place to keep that strong reference.
struct MyContainerStruct : IDLookable {
var id : Int = 0
weak var object : MyClass?
init(id : Int, object:MyClass) {
self.id = id
self.object = object
}
}
class Scope {
// ref count = 1
var object = MyClass(id: 11)
var structContainer : MyContainerStruct
init() {
// ref count = 1
structContainer = MyContainerStruct(id: 222, object: object)
messWithAClassInAStruct()
}
func messWithAClassInAStruct() {
// ref count = 1
var structContainerTwo = structContainer
structContainerTwo.id = 333
structContainerTwo.object // 11
}
}
let test = Scope()
I have two properties in my class. See this terrible example:
var length
var doubleLength
How do I initialize doubleLength based on length?
init() {
self.length = ...
self.doubleLength = self.length * 2
super.init()
}
I get an error that I can't access self before I call super.init(). Well I need to set all my variables before I can even call super.init() so what am I supposed to do?
if self.doubleLength is always supposed to be twice self.length (in this example) have you considered just using a computed property?
class MyClass: MySuperClass {
var length: Double
var doubleLength: Double {
return self.length * 2
}
init(len: Double) {
self.length = len
super.init()
}
}
You can temporarily delay the initialization of doubleLength an implicitly unwrapped optional, which will allow to temporarily assign a value to nil and assign it at a later time.
class Something: UICollectionViewLayout {
var doubleLength: Int! = nil
var length: Int {
return 50
}
init() {
super.init()
doubleLength = length * 2
}
}
Anyway, in this specific case I think it would be nicer to make doubleLength a computed property, since it can be always be computed from the value of length. Your class will be like
class Something: UICollectionViewLayout {
var doubleLength: Int {
return length * 2
}
var length: Int {
return 50
}
}
Thanks for your full reproduction, which is:
import UIKit
class Something: UICollectionViewLayout {
var doubleLength: Int
var length: Int {
return 50
}
init() {
doubleLength = length * 2
super.init()
}
}
From this we can see that you're using a getter to return your property. I think this is what's causing the problem. For example, if you just do this:
import UIKit
class Something: UICollectionViewLayout {
var doubleLength: Int
// Simple variable, no code.
var length = 50
init() {
doubleLength = length * 2
super.init()
}
}
...then that works fine.
I believe this is because the Swift compiler is trying to prevent you from doing anything that might mean you use the base class's methods, properties or variables before it's been initialised. I know you're technically not, in your example, but consider how hard it is to trace back and see what's being done from your initialiser. For example, if you were to do:
var length: Int {
// Where "width" is a made-up property of UICollectionViewLayout
return width * 3
}
...then your code would be run from your initialiser and use a property of UICollectionViewLayout before its own init had been called, therefore making it possibly invalid.
So my best guess is that this is the Swift compiler making a blanket ban on calling out to any code outside the subclass initialiser before the super is initialised.
You get exactly the same error if you do this, for example:
class Something: UICollectionViewLayout {
func foo() {
// Do nothing
}
init() {
foo() // error: 'self' used before super.init call
super.init()
}
}
The place I remember this being explained is the "Intermediate Swift" video from WWDC 2014, from slide 191, about 20 minutes in, but I'm guessing it's somewhere in the book, too...
A property that depends on another is bad practice. Just like when you design a database, you avoid calculated fields, when you design classes, you also avoid calculated fields. Instead of having a doubleLength property, you should instead have a getDoubleLength method that returns the length * 2.