Menu

Day 11 - Tic Tac Toe and...crash

Sep 10, 2015 at 10:10 am, by Pierre Liard

It was one of these days...I was thinking at one point into the tutorial I wouldn't be able to report anything about the Tic Tac Toe app started yesterday, except failure and an unexplained crash. I was ready to move on when I eventually found a cryptic solution on the web. It was however useless for solving the crash issue at hand because it didn't give any satisfactory explanation. I just did what I thought would be right and...it worked. It was just probably beginner's luck, but this experience was really frustrating for the mind.

Near the end of yesterday's post, I explained that the "sender" parameter in the function "ButtonPressed" can be used to find which button has been pressed. I need however to know which one of these buttons has been tapped, if I want to use this information in my code. Swift offers a nice way around that. When bringing up the Attributes Inspector in Xcode's right panel, and scrolling down, there is a field named tag that can be added to each of the buttons. By having a different tag for each of the crosses or zeroes, it becomes then possible to determine which one has been pressed:

filed tag in Xcode

When each box in the storyboard has been tagged with a unique number, it can be called, when tapped, by simply adding to "sender" the attribute "tag":

@IBAction func buttonPressed(sender: AnyObject) {
          var image = UIImage(named: "cross.png")
          sender.setImage(image, forState: .Normal)
          print(sender.tag)
}

In this particular example, the tag number of each button pressed will be printed in the console. I won't demonstrate the entire game, but I hope you got the idea: because each button is tagged, it's always possible for the compiler to know in which state each box is. For whose who are interested in the whole code, you can find it in this Stackoverflow.com post

To make this app more user friendly, Rob added a label and a button appearing progressively only when the game is over. The label shows which of crosses or naughts is the winner, and the button allows to replay the game. To show these two items, a UIView class in coordination with a method is necessary to animate them and give the illusion of movement:

@IBAction func buttonPressed(sender: AnyObject){
            UIView.animateWithDuration(0.1, animations: {() -> Void in
      self.gameOverLabel.center=CGPointMake(self.gameOverLabel.center.x - 400,
 self.gameOverLabel.center.y)
 
      self.playAgainButton.center = CGPointMake(self.playAgainButton.center.x - 400,
 self.playAgainButton.center.y) 
      })
}

This code determines an animation of a duration of 0.1 second, and moves the button and the label from the coordinate x in the storyboard to a location of x minus 400px, or in other words, in a position outside of the display. To make them reappear, the same code is used , but with with x plus 400px this time. The animation part of this game was in fact the only new section, but was unfortunately not explained enough to make us discover its potential in making objects moving into a display. For game developers out there, these features seem to be almost limitless.

It is at this point that started the beginning of the end, if I can say so. The game seemed running just fine when I first started it but, after hitting the button "Play Again" for the first time, it crashed unexpectantly and gave me this nasty message:

app crash message

If I understand properly the warning, the failure is due to the impossibility for Swift to convert the type UIImageView to UIButton. This makes sense: we have seen several times already that a type cannot be converted to another type without a cast. The conversion of the type string 10 to the type integer 10 is done for example as follows:

@IBAction func buttonPressed(sender: AnyObject){
         var myString = "10"
         var myInteger = 5
         var result = myInteger + Int(myString)!

In our game, the method viewWithTag(i) is of type UIView and cannot consequently be implicitly casted to a type of UIButton. In other words, the tagged boxes are not from the same type as buttons. It makes again perfect sense, but it doesn't explain why the code compiles without an hitch. The funny thing is that Rob's app also crashed in the video. So what did go wrong? You may remember that zero was one of the numbers used to tag the nine boxes in the board game. Zero is also the default tag, meaning that each object in the board will have a default tag of zero. When trying to access the top left box with its tag of zero, we are also getting the label for the game over, the button to restart the game, and even the image (the grid) in the background. The logical step to solve this issue is to give a tag other than zero to the other objects, in order to have only one item with a zero tag. Rob gave a tag of ten to the objects not directly related to the game:

tag number 10

The items highlighted in light grey are those receiving the tag 10. I personally gave a unique identifier to these 4 objects, because they are unique. So now, everything should work as intended. Unfortunately...not! The crash occurred again. This time, I had really no idea why. By scouring the Internet, I found the previous Stackoverflow.com link. By the way, I found the exact same demand on several other websites, with exactly the same answer: Problem Solved. The way i did it was that I moved my button with 0 tag after my board. This person must have been really impatient to know the solution to post the same question in several forums, but what really does mean his answer? In the View Controller Scene depicted in the last shot, the button with the zero is the last of the list, just before the label. By looking more in details, I noticed that the numbering of the tags were not in order: I had for instance tag 7 before tag 1. I reordered them and...wonder, no crash. It finally worked. I can only assume that Swift needs to have the button tags in their numeric order, but it is just an hypothesis. Order doesn't usually really matter, but I could only observe it was working by doing so. Moreover my mind was not satisfied and I haven't yet found a rational explanation to the phenomenon. Out of curiosity, I dug deeper into Robs's own code and guess what I found: he moved the zero tag after the board, like suggested in the website:

Rob's controller view

Without telling his students? Coincidence? I don't know, but one thing is sure: this 52 minutes video is much too long and is built on the wrong foundation. It looked a little bit like these clothes repaired so many times that they finish having holes everywhere. In addition, and it's the least I can say, this app is pretty rough on the edges, because it hasn't been tested properly.

This is frustrating and discouraging. It was in particular because of such flaws I gave up last year: too many errors, code working more or less, sometimes even less than more, poor sound quality, and this impression that the entire tutorial has been somehow improvised. I generally like improvisation, but I would prefer a little bit more rigor in this situation because it can give the wrong impression that coding is just about creativity and improvisation. It is somehow as such, but not when you're learning. It personally confuses and annoys me. In the final, building this app wasn't fun at all, but was more of a task you go through the motions. Hopefully the upcoming lectures will be better....


Leave a comment

Login to comment a post