My function is the one below
I'm trying to disable text when array reaches its limit.
I'm getting an error of array out of range. What type of condition can I use so that array is disabled when array1.count is equal to swipeCount.
This is my code:
let array1 = ["a","b","c","d"]
func getRandom1() {
for var i = 0; i < array1.count ; i++
{
array1.shuffle1()
}
}
func getText1() {
self.display.text = "\(array1[i++])"
swipeCount++
}
func getTextBack() {
self.display.text = "\(array1[i])"
}
func handleSwipes(sender:UISwipeGestureRecognizer) {
if (sender.direction == .Right)
{
if swipeCount != array1.count
{
getText1()
}
else
{
getTextBack()
}
}
}
func handleSwipes(sender:UISwipeGestureRecognizer) {
if (sender.direction == .Right) {
let aCount = array1.count - 1
if swipeCount < aCount
{
getText1()
}
else
{
getTextBack()
}
}
Change this line:
if swipeCount != array1.count
to
if swipeCount < array1.count - 1
I think you cannot use i in the getText1 and getTextBack. Instead of using i, you should use swipeCount like so:
func getText1() {
self.display.text = "\(array1[swipeCount++])"
}
func getTextBack() {
self.display.text = "\(array1[swipeCount])"
}
Related
I'm working on a chat app and the issue I'm having is with pagination. I'm able to load the first batch of documents and when I scroll to the top to load the next batch, it loads but instead of keeping the first batch of documents, it removes them. I'm not sure what I'm missing or doing wrong. Any help is greatly appreciated. Here is my code:
VC
var messages = [Message]()
var lastDocument: DocumentSnapshot? = nil
var fetchMoreDocs = false
func fetchChatMessages() {
fetchMoreDocs = true
var query: Query!
if messages.isEmpty {
query = MESSAGES_COLLECTION.document(currentUID!).collection(user.memberId).order(by: TIMESTAMP).limit(to: 5)
} else {
query = MESSAGES_COLLECTION.document(currentUID!).collection(user.memberId).order(by: TIMESTAMP).start(afterDocument: self.lastDocument!).limit(to: 5)
}
query.addSnapshotListener { (snapshot, error) in
if let error = error {
print("Error..\(error.localizedDescription)")
} else if snapshot!.isEmpty {
self.fetchMoreDocs = false
return
} else {
self.messages = Message.parseData(snapshot: snapshot)
DispatchQueue.main.async {
self.chatRoomTV.reloadData()
self.scrollToBottom()
self.fetchMoreDocs = false
}
}
self.lastDocument = snapshot!.documents.last
}
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
let position = scrollView.contentOffset.y
let maxOffset = scrollView.contentSize.height - scrollView.frame.size.height
if maxOffset - position <= -50 {
fetchChatMessages()
}}
func scrollToBottom() {
if messages.count > 0 {
let index = IndexPath(row: messages.count - 1, section: 0)
chatRoomTV.scrollToRow(at: index, at: UITableView.ScrollPosition.bottom, animated: false)
}}
I have a UIPickerView that is used to play the game Go Fish so data in it is continuously changing. AFter a few selections with the array I eventually get the error "Fatal Error: Index Out of Range" in the console and the error "thread 1 exc_bad_instruction (code=exc_i386_invop subcode=0x0)" on another line. Any idea on what is causing this and how to fix it.
Code:
import UIKit
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
///Main Section///
//Game
#IBOutlet weak var GameCardsLeft: UILabel!
//CPU
#IBOutlet weak var CPUCardsLeft: UILabel!
#IBOutlet weak var CPUPairs: UILabel!
//Player
#IBOutlet weak var UserPairs: UILabel!
#IBOutlet weak var pickerView: UIPickerView!
//Variables
var deck = [Card]()
//Creates a deck of cards
func createDeck() {
var i = 0 //Suite
while(i < 2) {
var s = "" //suite
var x = 1 //Value
if(i == 0) {
s = "Clubs"
}/* else if(i == 1) {
s = "Spades"
} else if(i == 2) {
s = "Diamonds"
}*/ else {
s = "Hearts"
}
while(x < 14) {
let tempCard = Card()
tempCard.value = x
tempCard.suite = s
tempCard.assignRank(value: tempCard.value)
tempCard.setDescription(rank: tempCard.rank, suite: tempCard.suite)
x += 1
deck.append(tempCard)
}
i += 1
}
}
//Shuffles the deck
func shuffle() {
var tempDeck = [Card]()
while deck.count > 0 {
let random = Int(arc4random_uniform(UInt32(deck.count)))
let card = deck.remove(at: random)
tempDeck.append(card)
}
deck = tempDeck
}
///Go Fish Section///
var drawDeck = [Card]()
var playerDeck = [Card]()
var playerPairsArray = [Card]()
var cpuDeck = [Card]()
var cpuPairsArray = [Card]()
var selectedCard = Card()
var gameOver = false
var randomIndex = 0
func deal() {
for card in deck {
if(playerDeck.count < 5) {
playerDeck.append(card)
} else if(cpuDeck.count < 5) {
cpuDeck.append(card)
} else {
drawDeck.append(card)
}
}
}
//Player draw card
func playerDraw() {
if(playerDeck.count == 0) {
while(playerDeck.count != 7) {
if(drawDeck.count > 0) {
playerDeck.append(drawDeck[0])
drawDeck.remove(at: 0)
} else {
break
}
}
} else {
if(drawDeck.count > 0) {
playerDeck.append(drawDeck[0])
drawDeck.remove(at: 0)
}
}
}
//CPU draw card
func cpuDraw() {
if(cpuDeck.count == 0) {
while(cpuDeck.count != 7) {
if(drawDeck.count > 0) {
cpuDeck.append(drawDeck[0])
drawDeck.remove(at: 0)
} else {
break
}
}
} else {
if(drawDeck.count > 0) {
cpuDeck.append(drawDeck[0])
drawDeck.remove(at: 0)
}
}
}
//Player's turn check cpu hand
func checkCPUHand(selectedCard: Card) {
var x = 0
while(x < cpuDeck.count) {
if(selectedCard.value == cpuDeck[x].value) {
playerDeck.append(cpuDeck[x])
cpuDeck.remove(at: x)
checkForPlayerPairs()
return
} else {
x += 1
}
}
playerDraw()
}
//CPU's turn check player hand
func checkPlayerHand(selectedCard: Card) {
var x = 0
while(x < playerDeck.count) {
if(selectedCard.value == playerDeck[x].value) {
cpuDeck.append(playerDeck[x])
playerDeck.remove(at: x)
checkForCPUPairs()
return
} else {
x += 1
}
}
cpuDraw()
}
//Check for player Pairs
func checkForPlayerPairs() {
var i = 0
var k = 0
var pairFound = false
while(i < playerDeck.count) {
pairFound = false
k = i + 1
while(k < playerDeck.count) {
if(playerDeck[i].value == playerDeck[k].value) {
pairFound = true
break
} else {
k += 1
}
}
if(pairFound) {
playerPairsArray.append(playerDeck[i])
playerDeck.remove(at: k)
playerDeck.remove(at: i)
} else {
i += 1
}
}
}
//Check for cpu pairs
func checkForCPUPairs() {
var i = 0
var k = 0
var pairFound = false
while(i < cpuDeck.count) {
pairFound = false
k = i + 1
while(k < cpuDeck.count) {
if(cpuDeck[i].value == cpuDeck[k].value) {
pairFound = true
break
} else {
k += 1
}
}
if(pairFound) {
cpuPairsArray.append(cpuDeck[i])
cpuDeck.remove(at: k)
cpuDeck.remove(at: i)
} else {
i += 1
}
}
}
/* Start of PickerView Stuff */
//Returns the number of columns
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
//Returns the number of rows
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return playerDeck.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return playerDeck[row].description //Error is in this line(thread 1 exc_bad_instruction (code=exc_i386_invop subcode=0x0))
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
selectedCard = playerDeck[row]
//have var = pickerData[row]
}
/* End of PickerView Stuff */
func organizeCardDeck() {
playerDeck = playerDeck.sorted { $0.value < $1.value }
cpuDeck = cpuDeck.sorted { $0.value < $1.value }
}
func start() {
createDeck()
shuffle()
shuffle()
deal()
organizeCardDeck()
checkForPlayerPairs()
checkForCPUPairs()
GameCardsLeft.text = "\(drawDeck.count)"
CPUCardsLeft.text = "\(cpuDeck.count)"
CPUPairs.text = "\(cpuPairsArray.count)"
UserPairs.text = "\(playerPairsArray.count)"
}
func checkGameOver() {
if(cpuDeck.count == 0 && playerDeck.count == 0 && drawDeck.count == 0) {
let cpuPairCount = cpuPairsArray.count
let playerPairCount = playerPairsArray.count
playerDeck.removeAll()
cpuDeck.removeAll()
deck.removeAll()
cpuPairsArray.removeAll()
playerPairsArray.removeAll()
/*if(playerPairCount > cpuPairCount) {
let alertController = UIAlertController(title: "Game Over", message: "You win", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "Restart", style: .default, handler: nil)
alertController.addAction(defaultAction)
} else if(playerPairCount < cpuPairCount) {
let alertController = UIAlertController(title: "Game Over", message: "You lose", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "Restart", style: .default, handler: nil)
alertController.addAction(defaultAction)
} else if(playerPairCount == cpuPairCount) {
let alertController = UIAlertController(title: "Game Over", message: "Tie game", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "Restart", style: .default, handler: nil)
alertController.addAction(defaultAction)
}*/
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.pickerView.delegate = self
self.pickerView.dataSource = self
/*var alert = UIAlertController(title: "Go FIsh Go", message: "", preferredStyle: .alert)
var startAlert = UIAlertAction(title: "Start", style: .default, handler: nil)
alert.addAction(startAlert)
present(alert, animated: true, completion: nil)*/
start()
}
#IBAction func SelectCard(_ sender: UIButton) {
checkCPUHand(selectedCard: selectedCard)
checkForPlayerPairs()
pickerView.reloadAllComponents()
pickerView.selectRow(0, inComponent: 0, animated: true)
if(playerDeck.count == 0 && drawDeck.count > 0) {
playerDraw()
}
GameCardsLeft.text = "\(drawDeck.count)"
CPUCardsLeft.text = "\(cpuDeck.count)"
CPUPairs.text = "\(cpuPairsArray.count)"
UserPairs.text = "\(playerPairsArray.count)"
randomIndex = Int(arc4random_uniform(UInt32(cpuDeck.count)))
checkPlayerHand(selectedCard: cpuDeck[randomIndex])
checkForCPUPairs()
if(cpuDeck.count == 0 && drawDeck.count > 0) {
cpuDraw()
}
GameCardsLeft.text = "\(drawDeck.count)"
CPUCardsLeft.text = "\(cpuDeck.count)"
CPUPairs.text = "\(cpuPairsArray.count)"
UserPairs.text = "\(playerPairsArray.count)"
checkGameOver()
}
}
Change return playerDeck[row].description to: return (row < playerDeck.count ? playerDeck[row].description : nil), and change selectedCard = playerDeck[row] to:
if row < playerDeck.count {
self.selectedCard = playerDeck[row]
}
Also, call self.pickerView.reloadAllComponents() right before returning from your deal, playerDraw, checkCPUHand, checkPlayerHand, checkForPlayerPairs, organizeCardDeck, and checkGameOver functions, and any other functions that modify playerDeck.
For a String which have both String and Int values (one of each) is it possible to do simple sort that will give the items ordered in numerical order as the primary order and alphabetical as the secondary order
var nameArray = ["Dave7", "Bob8", "Cathy9", "Henry10", "Susan10", "Pat11", "Steve12", "Dan12", "Ken1", "Sean2", "Howard3", "Dixie3", "Newman5", "Billy6"]
var sortedNameArray = nameArray.sort { $0.compare($1, options: .NumericSearch) == .OrderedAscending }
print(sortedNameArray) // gives the following:
Don't want this -> ["Billy6", "Bob8", "Cathy9", "Dan12", "Dave7", "Dixie3", "Henry10", "Howard3", "Ken1", "Newman5", "Pat11", "Sean2", "Steve12", "Susan10"]
Even though .NumericSearch was used the result is alphabetical.
I was able to get the desired result using a custom binary tree. Which gives the results:
Ken1 Sean2 Dixie3 Howard3 Newman5 Billy6 Dave7 Bob8 Cathy9 Henry10 Susan10 Pat11 Dan12 Steve12
But is there a simpler solution?
extension String {
var integerValue: Int? {
return Int(self)
}
}
func extractValueFromString(theString:String)->Int{
var catNumber: [Character] = []
//print("theString \(theString)")
for character in theString.characters{
var characterString = String(character)
if var value = characterString.integerValue { //if we don't check program crashes
//if numberSet.contains(Int(String(character))!) { //another way to check but redundant here
catNumber.append(character)
//print(catNumber)
// }
}
}
let numberString = String(catNumber)
return Int(numberString)!
}
class Node{
//nodes now only arrange strings
var data = ""
var value = Int()
var left:Node?;
var right:Node?;
deinit {
//print("deleting \(data)")
// print("node deleted")
}
init(data:String){
self.data = data;
//print(data)
}
}
class binaryTreeSort{
var root:Node?
init(){
}
deinit {
//print("tree deleted")
}
func getRoot()->Node{
return root!
}
func insertNewValue(data:String){
let newNode = Node(data:data)
var node:Node? = root
if (node == nil){
root = newNode
}
while (node != nil) {
let currentValue = node?.data
if currentValue == ""{
node?.data = data
return
}
if currentValue == data {
//we don't want duplicates.
return
}
if extractValueFromString(currentValue!) < extractValueFromString(data) {
if (node!.right != nil) {
node = node!.right
//print("Going Right at data \(node!.data)")
}else{
node!.right = newNode
//print("Going New Right at data \(node!.data)")
return
}
}else if extractValueFromString(currentValue!) == extractValueFromString(data){
if currentValue < data {
if (node!.right != nil) {
node = node!.right
//print("Going Right at data \(node!.data)")
}else{
node!.right = newNode
//print("Going New Right at data \(node!.data)")
return
}
}else{
if (node!.left != nil) {
//print("Going Left at data \(node!.data)")
node = node!.left
}else{
node!.left = newNode
//print("Going New Left at data \(node!.data)")
return
}
}
}
else{
if (node!.left != nil) {
//print("Going Left at data \(node!.data)")
node = node!.left
}else{
node!.left = newNode
//print("Going New Left at data \(node!.data)")
return
}
}
}
}
func inorderPrint(baseNode:Node){
if(baseNode.left != nil)
{
inorderPrint(baseNode.left!);
//print(" \(baseNode.data)")
}
print("\(baseNode.data)")
if(baseNode.right != nil)
{
inorderPrint(baseNode.right!)
//print(" \(baseNode.data)")
}
}
func reverseOrderPrint(baseNode:Node){
if(baseNode.right != nil)
{
reverseOrderPrint(baseNode.right!)
//print(" \(baseNode.data)")
}
print("\(baseNode.data)")
if(baseNode.left != nil)
{
reverseOrderPrint(baseNode.left!);
//print(" \(baseNode.data)")
}
}
}
var myBinaryTreeSort:binaryTreeSort? = binaryTreeSort()
for item in nameArray{
//print(item)
myBinaryTreeSort!.insertNewValue(item)
}
myBinaryTreeSort!.inorderPrint(myBinaryTreeSort!.getRoot())
print("---------------")
myBinaryTreeSort!.reverseOrderPrint(myBinaryTreeSort!.getRoot())
myBinaryTreeSort = nil //delete the tree
Use map to split the names into parts, sort to sort by number and name, and then map to restore the original:
func splitName(name:String) -> (String, Int) {
if let range = name.rangeOfCharacterFromSet(NSCharacterSet.decimalDigitCharacterSet()) {
return (name[name.startIndex..<range.startIndex], Int(name[range.startIndex..<name.endIndex])!)
} else {
return (name, 0)
}
}
print(nameArray.map(splitName).sort({ lhs, rhs in
if lhs.1 < rhs.1 {
return true
} else if lhs.1 > rhs.1 {
return false
} else {
return lhs.0 < rhs.0
}
}).map({ "\($0.0)\($0.1)" }))
Some other ways it could be done would be to maintain element 0 of the tuple as the full name (with numbers) and then the final map just becomes map({ $0.0 }) Depending on sizes, this may be more optimal than splitting the name each time it's compared.
If you have an array, you can sort with a custom closure.
For example:
nameArray.sort({extractValueFromString($0) < extractValueFromString($1)})
Will get you close. You just need to check if they are equal and return $0 < $1 instead.
Here's how I solved this, doing something similar to what #Lou-Franco alluded to:
func endInteger(word: String) -> Int {
if let range = word.rangeOfCharacterFromSet(NSCharacterSet.decimalDigitCharacterSet()){
let numberSubstring = word.substringFromIndex(range.startIndex)
return Int(numberSubstring) ?? 0
}
return 0
}
let sortedArray = yourArray.sort{endInteger($1) > endInteger($0)}
I have a working UITableView in which I added a UIRefreshControl like this:
var refresher: UIRefreshControl!
...
// this is ViewDidLoad()
// pull to refresh
refresher = UIRefreshControl()
refresher.tintColor = globalClass.blue
refresher.attributedTitle = NSAttributedString(string: "")
refresher.addTarget(self, action: "loadFriends", forControlEvents: UIControlEvents.ValueChanged)
friendTableView.addSubview(refresher)
This works well on other UITableViews, but not on this one for some reason. The spinner never really spins and just snaps to the top when the dragging stops. What could cause this?
EDIT: loadFriends function
//load friends
func loadFriends() {
globalClass.requestsIn = []
globalClass.requestsOut = []
globalClass.finalSections = []
globalClass.myFriends = []
finalSections = []
sectionsG1 = []
let queryIn1 = PFQuery(className:"Friendship")
queryIn1.whereKey("toUser", equalTo: PFUser.currentUser()!.username!)
let queryOut = PFQuery(className:"Friendship")
queryOut.whereKey("fromUser", equalTo: PFUser.currentUser()!.username!)
let query = PFQuery.orQueryWithSubqueries([queryIn1, queryOut])
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
if objects!.count == 0 {
self.friendtTableView.reloadData()
self.text()
} else {
for object in objects! {
let toUser:String = object["toUser"] as! String
let status:String = object["status"] as! String
if toUser == PFUser.currentUser()?.username {
if status == "pending" {
globalClass.requestsIn.append(object["fromUser"] as! String)
self.update()
} else if status == "approved" {
globalClass.myFriends.append(object["fromUser"] as! String)
globalClass.myFriends = globalClass.myFriends.sorted { $0.localizedCaseInsensitiveCompare($1) == NSComparisonResult.OrderedAscending }
self.update()
}
} else { if status == "pending" || status == "rejected" {
globalClass.requestsOut.append(object["toUser"] as! String)
self.update()
} else if status == "approved" {
globalClass.myFriends.append(object["toUser"] as! String)
globalClass.myFriends = globalClass.myFriends.sorted { $0.localizedCaseInsensitiveCompare($1) == NSComparisonResult.OrderedAscending }
self.update()
}
}
}
}
if self.tableSegment == 1 {
if globalClass.requestsIn.count == 0 {
self.friendTableView.reloadData()
self.text()
} else {
}
} else if self.tableSegment == 2 {
if globalClass.requestsOut.count == 0 {
self.friendTableView.reloadData()
self.text()
} else {
}
} else if self.tableSegment == 0 {
if globalClass.myFriends.count == 0 {
self.friendTableView.reloadData()
self.text()
} else {
}
}
self.refresher.endRefreshing()
} else {
}
}
}
How can I return from closure in swift?
func closure(result: (Int -> Void)) {
var next = 1
while (true) {
result(next)
}
}
This is the invocation of the function
closure() { result in
// here I need to return
}
There is no return from the while loop in the question. In order to return there must be some conditional statement that will exit the while loop, something like:
while (true) {
result(next)
if something == false {
break;
}
}
or:
var i = 0
while (true) {
if i++ == 4 {
break;
}
print(i)
}
or:
var i = 0
while (i <
print(i)
}