The following code
class ViewController: UIViewController {
#IBOutlet weak var knock: UIButton!
#IBOutlet weak var label: UILabel!
var count: Int = 0
var unlocked: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func knockKnock(sender: UIButton) {
if count < 20 {
label.text = "Knocked \(count) times."
} else if count > 19 && count < 40 {
label.text = "Knocked \(count) times."
label.textColor = UIColor.randomColor()
} else if count > 39 && count < 100 {
label.text = "That's enough."
label.textColor = UIColor.blackColor()
} else if count > 99 && count < 102 {
label.text = "I wish you hadn't done that."
label.textColor = UIColor.redColor()
} else if count == 103 {
label.text = "Fine, come in."
label.textColor = UIColor.greenColor()
count = 126
unlocked += 1
}
if unlocked > 0 {
self.performSegueWithIdentifier("InsideHomeSegue", sender:sender)
}
count += 1
}
is prematurely performing the Segue in
if unlocked > 0 {
self.performSegueWithIdentifier("InsideHomeSegue", sender:sender)
}
The segue is performed immediately the first time the button is pressed, which I do not understand, as at that point the code should be unreachable behind a false if statement, since int unlocked is initialized with 0
I have had similar problems which turned out to be issues with XCode itself rather than my code; I have looked through all the files I can find referencing any variables or objects in Interface Builder, checked for naming inconsistencies, rogue outlets, etc.
I still have a very shaky understanding of Segues, and would appreciate any detailed help anyone can offer.
The larger if / else if block worked properly all the way up to the final increment until Segue code was added.
Originally the self.performSegueWithIdentifier("InsideHomeSegue", sender:sender) line was inside the else if count == 103 { block; var unlocked: Int was added to combat the Segue issue to no avail.
I've read through several pages of the XCode documentation on Segues, but haven't found anything else I can try.
It's possible I've overlooked something incredibly obvious, but regardless, thanks for reading.
Cheers
EDIT: I have checked all outlets, it's the only Segue in the project currently and it isn't hooked up anywhere else. The Segue is activated on a button press, not immediately on View load.
Just like what my comment said, You've connected the segue with your button, so that the segue will alway execute. It has nothing to do with if clause.
You should connect with the ViewController instead of connecting with a button
You have to connect your two ViewController with a segue, giving it an identifier. Then, you can trigger the segue in this way.
self.performSegueWithIdentifier("segue_name_identifier", sender: self)
Here how you can easily set your segue.
I hope that this will help you.
Related
Here is the code of #IBAction func
#IBAction func touchCard(_ sender: UIButton) {
flipCount += 1
if let index = buttonCollection.firstIndex(of: sender) {
game.chooseCard(at: index)
updateViewFromModel() // I set breakpoint at here
}
}
Concentration.swift file, part of model of MVC
class Concentration {
var cards = [Card]()
var numberOfPairsOfCards: Int
var identifierOfOneAndOnlyOneCard: Int? {
didSet {
print("identifierOfOneAndOnlyOneCard: \(identifierOfOneAndOnlyOneCard)")
}
}
init(numberOfPairsOfCards: Int) {
self.numberOfPairsOfCards = numberOfPairsOfCards
for _ in 0..<numberOfPairsOfCards {
let card = Card()
cards += [card, card]
}
}
func chooseCard(at Index: Int) {
print("Index: \(Index)")
if !cards[Index].isMatched {
if let matchIndex = identifierOfOneAndOnlyOneCard, matchIndex != Index {
// check if cards match
if cards[matchIndex].identifier == cards[Index].identifier {
cards[matchIndex].isMatched = true
cards[Index].isMatched = true
}
cards[Index].isFaceUp = true
identifierOfOneAndOnlyOneCard = nil
} else {
// either no cards or 2 cards are face up
for flipDownIndex in cards.indices {
cards[flipDownIndex].isFaceUp = false
}
cards[Index].isFaceUp = true
identifierOfOneAndOnlyOneCard = Index
}
}
}
}
the code of func updateViewFromModel()
Card.swift file, part of model of MVC
struct Card {
var isFaceUp: Bool = false
var isMatched: Bool = false
var identifier = getUniqueIdentifier()
static var uniqueIdentifier: Int = 0
static func getUniqueIdentifier() -> Int{
uniqueIdentifier += 1
return uniqueIdentifier
}
}
These code are part of project concentration game from CS193p.
When I traced the code step by step, I found something confusing.
As mentioned before, I set a breakpoint at the line of
updateViewFromModel() in #IBAction func touchCard(_ sender:
UIButton)
Then I clicked 'Run' button of Xcode
The iPhone simulator came out.
the default UI image without any clicking
I clicked the first 'card'(actually, a button) from left to right in the first row
Xcode reacted and the UI remained the same as default
I started debug the code with LLDB, and I stepped into func updateViewFromModel()
When I stepped over to Line 64, it showed that the isFaceUp of the first card is true because I just clicked this card.
Let's go on, I stepped over to Line 68. Line 65 and 66 must be executed! What I think is that when executing Line 65 and 66, the
UI is supposed to change.But, why didn't the UI update timely?
I finished executing the left code in func updateViewFromModel because I didn't click any other card.
Finally it came to the end of #IBAction func touchCard, the UI still remained the same as default.
I clicked 'continue program execution' button, the UI responded correctly.I felt so weird.
What I want to figure out is that at Step 9 why didn't the UI update timely.
I will appreciate your help very much!
When you make changes on a view, it waits for a redraw cycle, thus the view won't be updated immediately. There is nothing wrong with IBAction, you put changes elsewhere and set a break point, it won't make any difference.
It may be due to slow simulators as i am also facing slow simulators issue i don't know if someone else also faced this or not, I doubt your facing this issue but i am not sure.
1- There is Nothing wrong with your code update your Simulators when working with Xcode 9.2 and simulators of IOS11.
2- Give it a try on your device
In a single VC app,
a info label is used to display textually the number of clicks of a button,
idea is to toggle the text on even/ uneven number of clicks. I did this ok,
but the problem came when I tried to link couple ( 9 ) UIButtons to the single IBAction where count and label updates happen. Here the label update lags one step behind the real count ( verified by print(counter) on Console).
May someone help why this happens?
I can do it of course with separate IBAction for each UIButton,
but one action and buttons tags works fine, so it would be nice to keep the code less by single IBAction.
import UIKit
class ViewController: UIViewController {
var player:Player = .cross
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.label.text = "Player \(player.rawValue) is on the move"
}
#IBAction func Move(_ sender: UIButton) {
if player == .cross {
player = .circle
} else {
player = .cross
}
print(sender.tag)
print("Player \(player.rawValue) is on the move")
self.label.text = "Player \(player.rawValue) is on the move"
}
#IBAction func button(_ sender: UIButton) {
if player == .cross {
player = .circle
} else {
player = .cross
}
print(sender.tag)
print("Player \(player.rawValue) is on the move")
self.label.text = "Player \(player.rawValue) is on the move"
}
}
// the move function is the common IBAction, which lags the label update
// the func button is action for a separate button, doing label updates correctly
// debug progress: similar code worked fine without lag on other desktop,
moreover working code there clean, lags when i run it on my desktop.
I have doubts it might be simulator issue.
For the record, my xcode did it's latest amend few days ago.
My app has 3 components:
A textfield where the user enters a number to see if the number is prime or not
A button that when pressed does an action to determine if the number is prime or not
A label that shows whether the number is prime or not
When the button is pressed, the whole app freezes(but does not crash)and I have no idea why. I tried searching about this online, but none have solved my problem.Is there anything I can check for errors, or what reasons can a button freeze an app.
Here is my code:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var text: UITextField!
#IBOutlet weak var label: UILabel!
var i = 2
#IBAction func buttonPressed(_ sender: Any) {
if let userEnteredText = text.text{
var isPrime = true
let number:Int = Int(userEnteredText)!
while i < number{
if number % i == 0{
isPrime = false
i = i + 1
}
if isPrime == true{
label.text = "\(number) is Prime"
label.textColor = UIColor.black
}else{
label.text = "\(number) is not Prime"
label.textColor = UIColor.black
}
}
}else{
label.text = "Error-Enter a positive integer"
label.textColor = UIColor.red
}
}
}
Because the i++ should be outside of the if statement
...
while i < number{
i = i + 1
if number % i == 0 {
isPrime = false
}
...
Please note : Since you are trying to compute something that can take sometimes, you'll have(when you learn a little more) to do this kind of computation outside of the main thread. Your apps locks because you are blocking the main thread which is the one controlling the UI/touch/interaction of your app. Look into dispatch_async
PPS : Learn how to point break point in XCode and step over/into, you'll be able to debug the flow of your app.
I have a +1 button and a -1 button and a label that starts at 0. My +1 button is working great, but for some reason, my -1 button isn't working. Can anyone help?
var sales = 0
#IBOutlet weak var numberOfSalesLabel: UILabel!
#IBOutlet weak var minusOneSaleOutlet: UIButton!
#IBAction func plusOneSale(sender: AnyObject) {
sales += 1
numberOfSalesLabel.text = "\(sales)"
if sales >= 1 {
minusOneSaleOutlet.hidden = false
}
}
override func viewDidLoad() {
}
#IBAction func minusOneSale(sender: AnyObject) {
sales -= 1
numberOfSalesLabel.text = "\(sales)"
if sales == 0 {
minusOneSaleOutlet.hidden = true
}
}
Anybody got any ideas why my minus button isn't working? I'm thinking it might have to do with me calling it as an outlet and as an action, but I'm not sure. Thanks!
p.s.-I'm not sure if this is normal.
Using the connections inspector you'll need to make sure all the connections are correct.
If at any point you delete an #IBAction from your code, then create another connection, the old one will still remain until you remove it properly from the connection inspector.
Each of your buttons should only be connected to a single #IBAction (touchUpInside)
Below is what the connections inspector looks like. The image is from one of my own projects, and shows a connected delegate. So yours will look a bit different.
If all else fails, remove all connections on this view (click the x) and link them up again by Ctrl dragging from your button, into the code viewer right on top of your #IBAction. Sometimes its just easier to start again.
I edited some code based on what others have pointed out, but I keep getting the error stated above, saying I sent an "unrecognised selector". The selector for my timer, originally the error, has been amended, but Xcode is still complaining.
Here is my code:
import UIKit
class ViewController: UIViewController {
#IBOutlet var instructionsNew: UILabel!
#IBOutlet var lockStatusNew: UIImageView!
#IBOutlet var timerText: UILabel!
#IBAction func hackLockButton(sender: AnyObject){
var counter = 0
let timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "updateCounter", userInfo: nil, repeats: true)
func updateCounter() {
timerText.text = String(counter++)
}
while(timerText.text == "1") {instructionsNew.text = "loading"}
while(timerText.text == "2"){instructionsNew.text = "loading."}
while(timerText.text == "3") {instructionsNew.text = "loading.."}
while(timerText.text == "4"){instructionsNew.text = "loading..."}
while(timerText.text == "5") {instructionsNew.text = "hack successful!"
lockStatusNew.image = UIImage(named: "unlocked.png")
timer.invalidate()
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Please help me spot the problem. Thanks!
The issue is, you added the updateCounter inside the hackLockButton function.
You should place the method outside that function and it will work.
#IBAction func hackLockButton(sender: AnyObject)
{
// Code here
}
func updateCounter()
{
timerText.text = String(counter++)
}
Suggestion:
You don't want to write while(timerText.text == "1") {instructionsNew.text = "loading"} for showing that label. It can cause an infinite loop and hang your UI. Instead use a switch case like:
switch(counter)
{
case 1: instructionsNew.text = "loading"
// Write other cases too
}
I think you really, really need to get your head around how a timer works.
Your application has a run loop. When the user does anything, the run loop will call the appropriate code in your program, runs the code, and finish when that code is run. For example when you tap on a button, the run loop will call your button callback function, wait for it to finish, and then it can wait for the next thing to happen.
A scheduled timer inserts calls into that run loop. So every second the run loop calls updateCounter. updateCounter should do some stuff, and then return. It's not supposed to wait in a while loop at all. The while () inside it is badly, badly wrong.
You also do some other things upside down. You use your timerText label to control things. That's wrong. The label should display things. The updateCounter can update the counter, but then all other actions should depend on the value of the counter, not on the value of a user interface label! Imagine your boss tells you to display not 1, 2, 3, 4, 5 but one, two, three, four, five. You obviously change what goes into the label. But with your code you have to change code everywhere that reads the text of the label. Now imagine you don't want one, two, three, but the right text in the user's language...