Crash set variable extension Swift [duplicate] - ios

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.

Related

Use getter and setter in swift to set variable extension [duplicate]

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.

Xcode 8 doesn't compile type-inferred property that is using `self` [duplicate]

This question already has an answer here:
Swift lazy instantiating using self
(1 answer)
Closed 5 years ago.
Here is a snippet of Swift code that compiles in Xcode 9.0, but not in Xcode 8.3.3:
class MyClass {
let myNumber: NSNumber = 3
lazy var myPropertyUsingSelf = Int(self.myNumber)
}
error: use of unresolved identifier 'self'
private lazy var myPropertyUsingSelf = Int(self.myNumber)
^~~~
I found that removing type inference solves the issue:
class MyClass {
let myNumber: NSNumber = 3
lazy var myPropertyUsingSelf: Int = Int(self.myNumber)
}
But I do not understand why that's the case.
Can someone explain that?
n.b. Using a closure works too.
But Swift cannot infer the type from a closure and forces you to explicitly declare the closure returning type, so I suppose it's simply the same solution as above.
As stated in swift evolution mailing list, a lazy property needs an explicit type annotation if its initial value refers to self, the reason is not cleared why it's needed.
If the type is specified then it's runs without any issues, like in your case.
class MyClass {
let myNumber: NSNumber = 3
lazy var myPropertyUsingSelf: Int = Int(self.myNumber) //works when type Int is specified for lazy property
}
Update: The issue has been fixed in Swift 4/Xcode 9 beta 3, lazy property initializers can now reference instance members without explicit self, and without explicit type annotation.
(reference this stackoverflow post)

How to use a mutable variable in CGFloat Extension in Swift 3 [duplicate]

This question already has an answer here:
Xcode 8 Beta 4 Swift 3 - "round" behaviour changed
(1 answer)
Closed 6 years ago.
I'm currently upgrading a forked Framework to Swift 3.
Working Swift 2 Code:
public extension CGFloat {
var roundToNearestHalf: CGFloat {
return round(self * 2)/2
}
}
In Swift 3, the return throws the compiler error : Cannot use mutating member on immutable value: 'self' is immutable.
I was able to find tons of documentations why a method of a Struct need to to mutable. But so far I'm not able to find a solution for a variable.
If I enter the keyword mutating, the compiler throws the error: Expected declaration
public extension CGFloat {
var roundToNearestHalf: CGFloat mutating {
return round(self * 2)/2
}
}
My research on this issue is, that the code seems to be misplaced - so it needs to be within a function.
public extension CGFloat {
mutating func roundToNearestHalf() -> CGFloat {
var roundToNearestHalf: CGFloat {
return round(self * 2)/2
}
}
}
Now the compiler complains about the `*``
Research on that issue brought me to this Thread, that suggests to use the round function the way I'm trying too.
Since this code obviously worked till Swift 3, I'd like to know why it does not anymore. Why does a var has to be declared as mutable now? And how do I need to declare the var roundToNearestHalf now? Help is very appreciated.
Immutable things now usually have past participle names.
joined(), reversed(), rounded() methods that support fluent chaining
where before there were lots of free functions in present tense that took an argument grammatically in accusative case
like join(x), round(x)... they grammatically look very similar, which made round look like it would change x even though it didn't. Now it does :)
Now everything is way more streamlined, that's the big API change everybody is talking about :)

ios - filter two arrays with objects Swift [duplicate]

This question already has answers here:
How to remove common items from two struct arrays in Swift
(3 answers)
Closed 6 years ago.
I have got two arrays with objects.
var filteredData:[MainData] = [MainData]()
var removeData:[MainData] = [MainData]()
struct MainData {
var open:NSTimeInterval
var works = [Visit]()
}
I want remove data from filteredData using function filter with parameter filteredData.open == removeData.open
I can't filter two arrays with objects.
You can try like this, first get an Array of open from removeData array and check that it is contains object from the filteredData Array opens.
let opens = removeData.map { $0.open }
filteredData = filteredData.filter { !opens.contains($0.open) }

Extending Array to append SKTextures [duplicate]

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)")
}

Resources