How to make sequence in Swift? - ios

I'm trying to make a simple sequence of two actions but Xcode is saying that I have an extra argument in call. I tried to translate Apples Obj-C example into Swift and it's not going very well. What am I doing wrong?
func dead() {
let animateAction = SKAction.animateWithTextures(self.catArray, timePerFrame: 0.09)
let ending = SKAction.runBlock(self.gameOver)
let sequence = SKAction.sequence(actions: animateAction, ending)
self.cat.runAction(sequence)
}

The sequence method of SKAction requires an Array of AnyObject. To fix this, you will need to call the method with the two actions you declared earlier in an array like this:
let sequence = SKAction.sequence([animateAction, ending])
self.cat.runAction(sequence)

Related

Adding Swift closure object to NSMutableArray and then removing it doesn't work - LEAK

I have some Swift code that interoperates with Objective C, and I noticed I'm leaking, I narrowed it down to NSMutableArray not removing my closure, here's a pure Swift snippet that reproduces the problem:
let myClosure : ((String?) -> ())! = { (fileName: String?) in
}
let arr = NSMutableArray()
arr.add(myClosure)
arr.remove(myClosure)
Did anyone encounter this -- why does this happen? and how can I get it to work?
The closure doesn't have the reference so the array is unable to compare for removing your closure object that's why this will not remove from the array.
Your code
let arr1 = NSMutableArray()
arr1.add(myClosure)
print(arr1) //("(Function)")
arr1.remove(myClosure)
print(arr1) //("(Function)")
Solution
var arr = Array<Any>()
arr.append(myClosure)
print(arr) //[(Function)]
arr.remove(at: 0)
print(arr) //[]
This will remove by index so you have to use the index for removing the element instead of closure instance also I recommend you to use pure swift classes in Swift.
To re-emphasize, our codebase uses Swift that interops with ObjC, therefore, in my case its not possible to go pure Swift trivially.
I changed our API to use an NSDictionary that maps from NSUInteger handle to the closure and that integer is then used for removal of the closure from the dictionary.
The purpose of that API is to register listener callbacks and have a facility to unregister them. So that NSUInteger handle satisfies the removal bit.

If statements with arrays in swift

I am having some trouble with my swift code. I want to make an endless game similar to the line zen, where a random node appears from the top. I used this code to help use the randomizer:
let randomWallNameIndex = Int(arc4random_uniform(2))
let wallNames = ["obsticle #1", "obsticle #2"]
//can also be [1, 2,]
if wallNames == "obsticle #1"{
//insert code here
}
Although, I'm having trouble using the if statement to tell whether a specific number was selected and I can spawn that certain node.
Can someone find the solution?
let randomWallNameIndex = Int(arc4random_uniform(2))
let wallNames = ["obsticle #1", "obsticle #2"]
//can also be [1, 2,]
let wall = wallNames[randomWallNameIndex]
if wall == "obsticle #1"{
//insert code here
}
Just add a variable that holds the string from the array at that index and use that variable in the if statement.

Putting array into label in swift

#IBAction func generateBtn(sender: UIButton) {
let strt = UInt32(strtNum.text!)
let end = UInt32(endNum.text!)
let ttlNums = Int(amtNums.text!)
let x = RandomNum()
var z = 0
while z<ttlNums{
let y = x.rndNumGen(strt!, end: end!)
z += 1
var h = [String]()
h.append(String(y))
let display:String = h.joinWithSeparator(", ")
winningNums.text = display
print (display)
}
}
I don't know what is wrong with this code. I am trying to put the string display into the label and it prints out the last number from the random number generator. When i print it to the console it shows all of the random numbers.
The primary issue here is that your array is created fresh in every loop iteration, and your label is being set in every loop iteration. That means that the array will only ever contain the element made in that iteration, after which it's reset to a new array, and a new element is added. The array needs to be initialized once at the start, and have elements added to it repeatedly in the loop, then put into the label once at the end.
#IBAction func generateBtn(sender: UIButton) {
guard let startText = strtNum.text, let start = UInt32(startText),
let endText = endNum.text, let end = UInt32(endText),
let ttlText = amtNums.text, let ttlNums = UInt32(ttlText) else {
//one of these is nil, handle it gracefully here
return
}
let randomGenerator = RandomNum()
var h = [String]()
h.reserveCapacity(ttlNums)
for _ in 0..<ttlNums {
let randomNum = randomGenerator.rndNumGen(start, end: end)
h.append(String(RandomNum))
}
let display = h.joinWithSeparator(", ")
winningNums.text = display
print(display)
}
I've made a few other changes to bring this code in line with Swift best practices and conventions:
Don't force unwrap. Use an if let or guard let binding to safely handle nil values.
Give your variables meaningful names. Avoid single-letter names except in specific instances.
Don't put spaces beside a function/method name and the proceeding brackets.
Don't use a while loop to iterate over a known range. Instead, use a for in loop.
Dn't type in t3xtspk, it mks ur code look lik an angsty teenagr wrote it. Autocomplete will finish off words for you, so you barely end up typing anyway. Make it easy and readable.
I would suggest you make a few changes yourself:
Rename generateBtn. Functions/methods DO things, they're actions. They should be named with verbs, or verb phrases. Perhaps try something like displayRandomArray.
Refactor the random array generation into its own method.
Rename RandomNum. By the looks of it, it's not a number at all, it's a random number generator. Perhaps try RandomNumberGenerator
Rename h.
Add code to deal with what happens when the .text is nil, or what happens when it contains a string that isn't a UInt32 (thus causing the UInt32 initializer to fail and return nil)

error: Generic parameter 'R.Generator.Element' cannot be bound to non-#objc protocol type 'AnyObject'

I am querying HealthKit and saving it to CoreData. I fetch the data in a separate class. In TableViewController I append the data to an array:
if NSUserDefaults.standardUserDefaults().boolForKey("weightSwitch") == true {
xAxisDatesArray.append(cdFetchWeight.queryCoreDataDate())
yAxisValuesArray.append(cdFetchWeight.queryCoreDataData())
and pass it at tableView.dequeueReusableCellWithIdentifier
myCell.xAxisDates = xAxisDatesArray[indexPath.row]
myCell.yAxisValues = yAxisValuesArray[indexPath.row]
In UITableViewCell I initialise the variables (yAxisValues, xAxisDates) and pass them into a charting library which takes the x and y values and plot a chart.
class TableViewCell: UITableViewCell, TKChartDelegate {
var xAxisDates = []
var yAxisValues = []
plot....
I need to get the min and max values of yAxisValues so that I can set the appropriate y-axis range to the data.
I have tried to get the min and max with the following code:
func rangeMinAndMax(){
let minYvalue = minElement(yAxisValues)
let maxYvalue = maxElement(yAxisValues)
}
But this generates the error: Generic parameter 'R.Generator.Element' cannot be bound to non-#objc protocol type 'AnyObject'
- Question: Why and how can I fix it?
Any help would be much appreciated !
The thing to do in a situation like this is to throw away all the misleading dross and boil it down to the simplest possible case:
let arr : [AnyObject] = [1,2,3]
let min = minElement(arr) // same error: "Generic parameter blah-de-blah..."
So, you see, minElement doesn't work on an array of AnyObject, and that's what the error is telling you. And the reason is obvious: an AnyObject is not a Comparable. There is no "minimum" for a bunch of AnyObject things; the entire concept of one AnyObject being "less than" another AnyObject is undefined. You need to cast your array down to an array of something that minElement can work on, namely a Comparable of some kind.
For example, in that code, I can fix the problem like this:
let arr : [AnyObject] = [1,2,3]
let min = minElement(arr as [Int])
That is the sort of thing you need to be doing. Of course, what you cast down to depends upon what these elements actually are. It looks to me as if will probably be Double and NSDate respectively, but that's just a guess; I don't know what's in your arrays. You do (presumably). Note that an NSDate is not a Comparable so you will have a bit more work to do with that one.

Best way to init an array of views in swift?

I'm writing a new subclass of UIView using swift. I want to have an array of views, and I want to instantiate them in the initial declaration, for clarity.
If this was an Int array, I could do something like this:
let values: [Int] = (0...4).map() { $0 }
and so I'm trying to come up with some sort of similarly swifty one-liner that will create an array of UIButtons, instead of Ints.
my first thought was (0...4).map() { UIButton.buttonWithType(.Custom) } but if I do this (or if I replace the UIButton code with, say NSObject()) I get an error saying that "'Transition' does not have a member named 'map'". I can, say, do map() { "\($0)" } and get an array of strings.
My next thought was just to get an array of ints first, and then use map on those to return buttons, like:
let values: [UIButton] = (0...4)
.map() { $0 }
.map() { UIButton.buttonWithType(.Custom) }
but this gives me the same error. What am I doing wrong, here?
Okay, the solution came to me pretty quickly: I guess I can't quietly ignore the variable of the closure I'm passing in to the map function; I need to ignore it explicitly. So to get my array of 4 buttons, I can use an _ in the map function, like this:
var buttons = (0...4).map() {_ in UIButton.buttonWithType(.Custom) }
or what I actually ended up using:
lazy var buttons: [UIButton] = (0...4).map() { _ in
let button = UIButton.buttonWithType(.Custom) as UIButton
self.addSubview(button)
return button
}

Resources