Cycle through array in iOS - ios

In this app I save an NSOrderedSet of cards to a "Subject" entity in core data so that users can quiz themselves. The card flips and drags in tinder like fashion well but in the update card method I'm having some trouble. The current card displays fine as I set that in view did load (the first card of the NSOrderedSet's array property). When I drag and update however it immediately goes to the last card, for example if I have 5 cards in a deck it will start with the first then immediately go to the fifth. What would be the best way to update this method so that it will cycle through as desired?
I suppose I should pass it an index property like a tableViewDelegate method but if someone has done something like this before and has a better way that's greatly appreciated.
Thanks for the help like always.
func updateCard() {
//cycle through questions here
for var i = 0; i < (self.subject.cards?.count)!; i++ {
self.currentCard = self.subject.cards?.array[i] as? Card
self.draggableView.questionLabel.text = self.currentCard?.question
self.draggableView.answerLabel.text = self.currentCard?.answer
}
}

Currently, when you call updateCard the for loop is computing at computer-speed and you only get to see the last index.
Here's one option:
In your class, set a stored variable called selectedCardIndex as an implementation detail and then just increment and update the view in updateCard.
var selectedCardIndex = 0
func updateCard() {
self.selectedCardIndex += 1
self.currentCard = self.subject.cards?.array[self.selectedCardIndex] as? Card
self.draggableView.questionLabel.text = self.currentCard?.question
self.draggableView.answerLabel.text = self.currentCard?.answer
}

Related

Adding a new array does not update my total array count in Swift Xcode

Problem: Initially my count is correct, however, adding a new array does not update my total array count label.
I have a View Controller (VC) that shows a label with a count of total arrays.
I have a Table View Controller (TVC) that arrays are added or deleted from.
I have a separate struct file to hold the arrays.
The label populates with the correct number of arrays when I run it. However, adding a new array item (via TVC) in the simulator does not update the label on the VC.
Questions:
Should I put the count in a function in VC? It is currently in the viewDidLoad()
Should I then call the function in TVC when adding or deleting an array?
If 2 is yes then do I reference the function in VTC? Would it simply be
updateCount() or do I have to reference the VC controller e.g.
ViewController.updateCount()
I have tried both ways but it does not seem to work, if I can get confirmation that would be great then I can make it work.
Thank you in Advance
My suggestion is bad but it works.
The easiest answer is use static variable, but it will cost memory phone. example code:
import Foundation
import UIKit
class VC: UIViewController {
static var count = 0
let label: UILabel = UILabel()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
label.text = String(VC.count)
}
}
class TVC: UITableViewController {
func updateCount() {
VC.count = VC.count + 1
}
}
Whenever function updateCount() called in TVC, and go back to VC class it will update the count.
My other suggestion is use MVVM pattern that sending VCViewModel as parameter to TVC. and update count in VCViewModel.
Other suggestion is use delegate pattern.
If you do something like this:
var x = 0
var y = x
x = 7
print(y) //y is still 0
You need to update the count whenever you change the amount of arrays. To call a view controller's function from another view controller, you need to use a protocol. I suggest you research how to make protocols in swift - I would help you but it's hard without being able to see the code.

Way to query whether an object is a member of an array?

I'm designing a FreeCell card game and I have both my cards (model) and cardViews (view) in arrays that represent columns of cards – and then the whole board is an array of columns:
//in the model:
typealias Card = DeckBuilder.Card
typealias Column = [Card]
var board = [Column](repeating: [], count: 8)
//in the view controller:
var boardForView = [[PlayingCardView]](repeatElement([PlayingCardView](), count: 8))
When a user taps on a cardView, I want the controller to take the selected cardView's column & row (where the column is which column in the board and the row is which card in the column) and then find the card in the corresponding position in the model.
I've got my tap gesture recognizer set up, and have extracted the cardView from it:
func selectCard(_ sender: UITapGestureRecognizer) {
if let selectedCard = sender.view as? PlayingCardView {
print("card selected: \(selectedCard.cardDescription?.string)")
}
}
So the question is: is there a property of the cardView that is its place in a column array, and then a property of that column that is the column's place in the boardForView array?
I figured it out! One way I had thought of was iterating through each card in each column of the board and checking to see if it == my current card. Seemed way too clunky. But then I found array.index(of: element) and my day is saved! I do have to iterate through each column on the board, but it's still much more elegant:
func selectCard(_ sender: UITapGestureRecognizer) {
if let currentCard = sender.view as? PlayingCardView {
for column in 1...boardForView.count {
if let row = boardForView[column - 1].index(of: currentCard) {
print("card selected: \(currentCard.cardDescription!.string) in row \(row+1) of column \(column)")
selectedCard = freeCellGame.board[column - 1][row]
print("card selected from model: \(selectedCard!.description)")
}
}
}
}
Since it's a board game, you surely have a logic set for how the board should be laid out. Make that logic work both ways. That is, use it to provide layout info while creating your board and also use it to get information about your board.
This way, when the gesture recognizer triggers, fetch the tap point and let your layout logic tell you the row and column of the card the tap came from.
Now, you can directly fetch the Card from your board property with those two indices (row and column).

Firebase filling array twice -- Swift

I have two String arrays: one that holds order numbers, and one that holds addresses.
I pull data from Firebase in viewDidAppear using a function that contains the following:
self.localOrderNumberArray.removeAll()
self.localAddressArray.removeAll()
self.orderNumbers.removeAll()
self.addresses.removeAll()
self.tableView.reloadData()
if onItsWayCompanyNameStoreNumberCourierNumberRootRef != nil {
let deliveryRef = onItsWayCompanyNameStoreNumberCourierNumberRootRef.childByAppendingPath("deliveries")
deliveryRef.observeEventType(.ChildAdded, withBlock: { snapshot in
self.orderNumbers.removeAll()
self.addresses.removeAll()
print(snapshot.value.objectForKey("orderNumber"))
let orderNumberPulledFromFirebase = snapshot.value.objectForKey("orderNumber") as! String
self.localOrderNumberArray.insert(orderNumberPulledFromFirebase, atIndex: 0)
let addressPulledFromFirebase = snapshot.value.objectForKey("address") as! String
self.localAddressArray.insert(addressPulledFromFirebase, atIndex: 0)
self.orderNumbers = self.localOrderNumberArray
self.addresses = self.localAddressArray
self.tableView.reloadData()
})
}
The function fills a UITableView with the data pulled from Firebase.
Everything works great when I first run the app. I can add data to Firebase through a different function, and the function above will pull the new data into the UITableView just fine.
However, when I segue to a different view controller (another UITableView, in this case), and then come back to the view that holds the function above, the function fills the order number and address arrays twice when I add new data.
If I segue to the other UITableView a second time, and then come back to view that holds the function above, the function fills the order number and address arrays three times when I add new data. And so on and so on.
It's the strangest thing. I can't figure it out, and it's about to drive me over the edge. Please help.
You are calling deliveryRef.observeEventType in viewDidAppear. viewDidAppear will be called each time the ViewController is presented. So when you segue to other ViewController and comes back, viewDidAppear will be called again and deliveryRef.observeEventType is registered again. So effectively there are two listeners doing the same job in your viewController which will add duplicate data to the array.
You have to implement a logic to do observeEventType only once in the ViewController.

Voting buttons with Parse in Swift

A quick overview of what I'm trying to make. I'm making an app to show my film reviews. I have a PFQueryTableviewController of which I use a custom cell. This table shows films which come from my Parse database. In each cell, there a 3 UIButtons, of which I want the user to use to vote for the film (happyVote, OkVote, sadVote). Over the top of each button is a UILabel that simply displays a count.
How I want it to work
When a user presses one of the buttons, the vote increases by 1.
When a user presses the same button again, the vote decreases by 1. Or,
If the user had pressed a different button, the vote decreases on the first button and increases on the button just pressed.
The user can only ever vote on one of the buttons.
The vote is shown by the UILabel showing the count, and by the button image changing.
See below for a visual:
This is what I've added in Parse:
So far, I've added the code to increase the vote count in Parse, in my TableViewController.swift:
#IBAction func upVoteButton(sender: AnyObject) {
let hitPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
let hitIndex = self.tableView.indexPathForRowAtPoint(hitPoint)
let object = objectAtIndexPath(hitIndex)
object!.incrementKey("UpVoteCount")
object!.saveInBackground()
self.tableView.reloadData()
}
This kind of works, except, the user can keep increasing the count, and they can vote on all 3 buttons. And it doesn't change the Button Image when pressed.
In my cellForRowAtIndexPath method, I've put:
let downVote = object!.valueForKey("DownVoteCount") as! Int
cell.downVoteLabel.text = "\(downVote)"
let middleVote = object!.valueForKey("MiddleVoteCount") as! Int
cell.middleVoteLabel.text = "\(middleVote)"
let upVote = object!.valueForKey("UpVoteCount") as! Int
cell.upVoteLabel.text = "\(upVote)"
I have searched for a while for some examples of how to figure the rest out, but can't find anything, and I'm really struggling to figure the next steps out.
Any help will be greatly appreciated, and please let me know if you need/want to see anymore of my code. Thanks
In your upVoteButton() method, you can add the other two buttons and set them button.enabled = false inside an if statement like:
if downVoteButton.enabled == true {
downVoteButton.enabled = false
} else if downVoteButton.enabled == false {
downVoteButton.enabled = True
}
And do the same with the middleVoteButton in antoher if statement or the same, whatever floats your boat, also within the other button methods with the appropriate buttons. This helps disables the buttons when pressed and then enables it when it's pressed again.
And for the image changing you can follow this.

Understand TableView and UISegmentedControl

I Need some help to understand how can I filter a information in Uitableview with UISegmentedControl. I have a UITabeView with data that contain two different data, Rec and Dat . I want to load ALL data when start application and separate Deb and Rec when user choose in UISegmentedControl. When I start application I populate 3 Array alls, recs and dats. I show the array alls, and want to change/filter the data when the user change the choose in UisegmentControl. Can you help me please ?
#IBAction func filtroDebitoCredito(sender: AnyObject) {
//when All
if FiltroControlerTable.selectedSegmentIndex == 0 {
// tableView.reloadData() ???
}
//When Creds
if FiltroControlerTable.selectedSegmentIndex == 1 {
// ???
}
//Debs
if FiltroControlerTable.selectedSegmentIndex == 2 {
// ???
}
Tks for help
Actually, you are already there. Your table view displays model data. So when the user changes the value of the segmented control, switch to the correct set of model data and, exactly as you say, tell the table to reloadData(). What I would do is have four arrays: model, all, recs, and dats. The table, let us say, always displays model. So the segmented control would copy, let us say, recs into model and tell the table view to reload!

Resources