This question already has answers here:
How to have stored properties in Swift, the same way I had on Objective-C?
(21 answers)
Closed 4 years ago.
I want to set a value for an SKSpriteNode. So, I made an extension to SKSpriteNode called HAKEK
I've tried this
var HAKEK: Int {
get {
return self.HAKEK
}
set {
self.HAKEK = newValue
}
}
But it doesn't work cause it keep returning it self, so how do I let It get its own value which is set in the setter?
You can't create stored properties in extensions as others have mentioned. Normally I would agree with others in using associated objects, but with SKNode, there is an even better property to work with.
It is called userData, and it is designed to allow your nodes to hold custom data.
extension SKSpriteNode
{
var HAKEK: Int {
get {
return self.userData?["HAKEK"] ?? 0
}
set {
self.userData = self.userData ?? [String:AnyObject]()
self.userData["HAKEK"] = newValue
}
}
}
Of course, I would not extend SKSpriteNode if this property is not going to be available to all SKSpriteNodes. If this is a unique case, you may want to sub class, which means this extension isn't even needed.
Related
I am new to Swift and maybe it's a stupid question, but I can't find an answer to it.
I have created an extension:
extension UITextField {
var placeholderLabel: UILabel {
get {
return self.placeholderLabel
}
set {
self.placeholderLabel = newValue
}
}
}
When the property is set, the application crashes.
You can't have a stored property in extension.
Extensions are not allowed to add a property to existing class because adding a property structure of the class will change. And because Objective C, Swift or any other programming language that am aware of could not afford it, it won't allow you to add the stored property to extension.
Isn't there any work around then ??
This is what you can do to save the label as stored property in your extension :)
import Foundation
import UIKit
fileprivate var ascociatedObjectPointer : UInt8 = 99
extension UITextField {
var myLabel : UILabel {
get {
return objc_getAssociatedObject(self, &ascociatedObjectPointer) as! UILabel
}
set {
objc_setAssociatedObject(self, &ascociatedObjectPointer, myLabel, .OBJC_ASSOCIATION_RETAIN)
}
}
}
How it works ??
Simple by writing setter and getter for the variable which you are posing or pretending to be stored property and by internally holding a pointer which has nothing to do with the existing class, hence it won't affect the structure of existing class.
Hope it helps.
You can use NSMapTable like this:
extension UITextField {
private static var placeholderLabelMap: NSMapTable<UITextField, UILabel> = .weakToStrongObjects()
var placeholderLabel: UILabel? {
get {
return UITextField.placeholderLabelMap.object(forKey: self)
}
set {
UITextField.placeholderLabelMap.setObject(newValue, forKey: self)
}
}
}
The advantage of Sandeep's answer might be thread safety. You can see this Stack Overflow topic for comparison between the approaches.
I'm currently learning ios developement using swift and I was just wondering if there is a way in xcode to
1) set a breakpoint on a variable whenever the value of the variable changes
OR
2) somehow track the change to variable value over time
Method with Swift didSet and willSet
You can use the print in the console:
class Observable {
static var someProperty: String? {
willSet {
print("Some property will be set.")
}
didSet {
print("Some property has been set.")
}
}
}
Method with watchpoints
Watchpoints are a tool you can use to monitor the value of a variable
or memory address for changes and trigger a pause in the debugger when
changes happen. They can be very helpful in identifying problems with
the state of your program that you might not know precisely how to
track down.
You can find a great guide here
I think you should learn about willSet and didSet concepts.
Swift has a simple and classy solution called property observers, and it lets you execute code whenever a property has changed. To make them work, you need to declare your data type explicitly, then use either didSet to execute code when a property has just been set, or willSet to execute code before a property has been set.
Update the value whenever the value was changed. So, change property to this:
var score: Int = 0 {
didSet {
scoreLabel.text = "Score: \(score)"
}
}
There is already a good question and answers which expalin this concept.
What is the purpose of willSet and didSet in Swift?
As far as I know, Swift allows us to set property observers for either stored and computed properties. But if computed property value depends on some backing store, property observers are not fired when these backing store values are changed:
public class BaseClass {
private var privateVar1: Int = 0
private var privateVar2: Int = 0
public var property: Int {
get {
return privateVar1 * privateVar2
}
set {
print("some setter without effect")
}
}
private func changeSomeValues() {
privateVar1 = 1
privateVar2 = 2
}
}
public class SubClass : BaseClass {
override var property: Int {
didSet {
print("didSet \(property)")
}
}
}
didSet of SubClass isn't called when changeSomeValues is called.
Let's consider a case: we have such BaseClass in a third-party framework. We define SubClass in our app. The question is: how can we rely on SubClass observers without knowledge about property nature: is it stored (and we can rely on observers) or computed (and then we can't expect firing observers each time when we expect it)? Is it possible? If no, is it an incapsulation violation?
That behaviour is perfectly normal. There is no way for the compiler to know which backing store really corresponds to which computed property. Your backing store in this case is made up of private variables that will not be accessible outside the class itself. So the only place where an "under the hood" change can occur is in the base class. It is that class's prerogative to use its calculated properties (which will trigger the observers) or the backstore (which will not).
In your example, assuming you never want to allow "invisible" changes, the changeSomeValues() function is breaking its own rules and not respecting the contract it promised to its subclasses and callers.
This question already has answers here:
Is it possible to make an Array extension in Swift that is restricted to one class?
(4 answers)
Closed 7 years ago.
Being fairly new to Swift I decided I would look at extending Array (or more specifically [SKTexture] Arrays of SKTexture) with a function to add a specified number of frames from the application bundle.
// FRAMES
FuzzyRabbit_0001#2x.png
FuzzyRabbit_0002#2x.png
FuzzyRabbit_0003#2x.png
FuzzyRabbit_0004#2x.png
// CALL
var rabbitTextures = [SKTexture]()
self.rabbitTextures.textureFromFrames("FuzzyRabbit", count: 4)
My first attempt is listed below, I am getting the error Cannot invoke 'append' with an argument list of type '(SKTexture!)' which from looking at the function fuzzyPush is because I am trying to append an SKTexture rather than the generic T.
Is this possible, or am I limited by the fact that I don't want the function to be generic but rather specific to Arrays of SKTexture.
extension Array {
// ONLY SKTexture
mutating func textureFromFrames(imageName: String, count: Int) {
if !(self[0] is SKTexture) { return }
for index in 1...count {
let image = String(format: "\(imageName)_%04d", index)
let texture = SKTexture(imageNamed: image)
self.append(texture) // ERROR: Cannot invoke append with an argument list of type SKTexture!
}
}
// WORKS FINE
mutating func fuzzyPush(newItem: T) {
self.append(newItem)
}
}
I was just curious if this is something I could do with an extension, its not a problem as I have this as a function that takes 3 parameters (imageName, count, arrayToAppend) so I can quite easily use that.
This extension is not possible to write today. You cannot apply an extension method to only certain types of arrays.
There are two good solutions. You can use a HAS-A pattern by creating a struct (TextureList) that contains a [SKTexture], or you can use a function.
You can replace :
self.append(texture)
with
self.append(texture as T)
I checked this on an array of strings though and it worked.
About the first check add another check to see if the array is empty otherwise the self[0] is SKTexture will fail.
This is the code I tested on an online swift compiler (SKTexture was not available obviously) :
extension Array {
mutating func textureFromFrames(imageName: String, count: Int) {
for index in 1...count {
let image = String(format: "\(imageName)_%04d", index)
self.append(image as T)
}
}
}
var arr = Array<String>()
arr.textureFromFrames("testing", count:4)
for tmp in arr {
println("\(tmp)")
}
This question already has answers here:
Property getters and setters
(12 answers)
Closed 8 years ago.
I got a crash when i try to set a variable inside a extension:
extension String {
var index: Int {
get {
return self.index
}
set {
self.index = newValue
}
}
}
var o: String = "tre"
o.index = 87 // crash here
println(o.index) // Even here
i tried everything, without any success.
Thanks in advance for your help.
You cannot add new stored variables to a type using extensions.
You are making a loop by infinitely setting or getting a property.
You cannot add new stored properties with extension, only computed ones that are not backed by a property.