Treehouse Intermediate Course - Part 18 (Build Interactive Story App Project 2)

Back in Dubai and back to the code! I knew yesterday would be a right off. But just to clarify, I do NOT need to code every day. I reckon that 3-4 times a week for 30 minutes to 1 hour. That may not hit the self-imposed three hours a week target. Realistically, however, with school about to start again, I cannot guarantee three hours a week. I need to put together my long term plan for coding, which I will actually do below. I need more vision and purpose for it. Having faced several setbacks with it, I can't let that deter me. These may seem like random, unconnected thoughts but they do actually link together. So, before continuing with Treehouse, let's map out my long term plan!

Step 1(June 2018-December 2018) - learn the basics syntax and principles of coding with Swift.

Step 2 (January 2019 - June 2019) - learn more intermediate level coding and create several of my own projects.

Step 3 (July 2019 to December 2019) - build on the intermediate concepts, learn some more advanced elements of Swift and create more complex mini apps/projects.

Step 4 (January 2020 to June 2020) - learn the highest order/most complex aspects of Swift. Use RayWenderlich newsletter, London App Brewery - any way of keeping up to date with knowledge and application of the most recent Swift. Make even more complex projects, which are near to 'app ready'.

Step 5 (approx July 2020 to December 2020) - Focus on building and developing apps. Tighten up on knowledge and go over any areas unsure about. Contribute to any online forums/discussions. Network with other Swift users.

Step 6 (approx January 2021 to June 2021) - Start looking at ways to make actual money from coding! Actually start selling apps on the app store, with the correct marketing/advertising strategies in place. Keep broadening and developing understanding of up-to-date Swift aspects

Step 7 (July 2021?!) - Focus on being an app developer...this will not be a quick, easy process and could take months. So the date is not really that relevant.

Step 8 - (Who knows?!) - Be a full time app developer. Could be creating courses or my own online content...Or could just be working on projects alongside others. Or a company. Who knows!


So, a lot of pipe dreaming there! From Step 5 it starts looking more daunting. But that's a whole year away! If I just keep up my couple of hours a week, I can do this.

At the moment I am on Step 3. I have basically until the end of December - by the end of this term plus some of the holiday to have done ALL of Treehouse intermediate (that's easily doable), plus the bits from the other Udemy courses (again, can't see why not!), plus have done more mini projects. Again, this is all fine! So with that positive, much-needed 'seeing the bigger picture' done, let's get back to the current Treehouse course. Useful to do!

Start Time - 17:11

Last time, it was very much an introduction to setting up the main storyboard with the correct picture assets etc. Pasan made this relatively easy with all of the correct sizes, including for the main screen. We embedded the navigation controller, so now we can have multiple view controllers and organise them more logically.

Creating A Story

The dictionary might be the best way - a key with a text value. Actually there are downsides. The dictionary is opaque - it is not ordered. Also optionals are returned each time. So before he says, I reckon either an array or a class is better. Or both!

We want the page to be decoupled and not hardcoded. Basically what that means is if we had every option per view controller for the story, that would be a LOT of designing and creating. What we want is the text, picture and options to be inserted onto a template each time.

Our goal is to create small objects that each do one main thing. OK, enums! Yes that makes sense - each case to represent a chapter in the story. Cool. There will be a loose connection between chapters but each one does not need to know about the next or previous one.

Dependency injection - apparently this is having just one page to have the objects changing around it. Not seguing etc. OK, new term!

Story Segments as Enum Members

Each member of the enum is its own 'chapter'.

enum Story {
    
        case returnTrip
        case touchDown
        case homeward
        case rover
        case cave
        case crate
        case monster
        case droid
        case home

}

We have computed properties needed for the enum. We need some text, artwork and sound effects!

Extensions apparently will be used - for the enum type.

extension Story {
    var artwork: UIImage {
        switch self {
        case .returnTrip:
            return UIImage(imageLiteralResourceName: "ReturnTrip")
        case .touchDown:
                return UIImage(imageLiteralResourceName: "TouchDown")
        case .homeward:
            return UIImage(imageLiteralResourceName: "Homeward")
        case .rover:
            return UIImage(imageLiteralResourceName: "Rover")
        case .cave:
            return UIImage(imageLiteralResourceName: "Cave")
        case .crate:
            return UIImage(imageLiteralResourceName: "Crate")
        case .monster:
            return UIImage(imageLiteralResourceName: "Monster")
        case .droid:
            return UIImage(imageLiteralResourceName: "Droid")
        case .home:
            return UIImage(imageLiteralResourceName: "Home")
        }

    }

Lots of issues on the question section. But the above worked fine - just needed to use that imageLiteralResourceName keyword.

*Approx 20 minute delay. Posted a comment on the forum! I finally figured out how to put in code on the community forum - it's with three backpacks ``` at the start and end of the code! Also, putting 'swift' to the right of the first set of backticks means that it colour codes it as it knows it is Swift. So that is pretty cool! Not going to go mad with this, but I felt the need to put a comment that worked on my Xcode that no one else had. Cool!

*5 min pause

Structure of a Page

So a new struct has been made. We need a choice option too with text to inform us. A button needed to go to the correct page.  String and page instance. We don't need a new Struct - we can use type alias instead!

Type alias - alternate name for a type.

OK I totally get type alias now. Here is a perfect example of when it is useful -

typealias Choice = (title: String, page: Page)

Now we are using this 'Choice' keyword every time instead of the laborious tuple above. NICE!

Under the hood.... a tuple is an anonymous struct! We could have made a separate struct with the same effect. But I'll stick with the type alias. 

struct Page {
  
    let story: Story
    
    typealias Choice = (title: String, page: Page)
    
    var firstChoice: Choice?
    var secondChoice: Choice?
}


Errors come up with the above though. Structs cannot use references to itself. 

A page contains a choice and a choice contains a page....there is an issue. 

class Page {
  
    let story: Story
    
    typealias Choice = (title: String, page: Page)
    
    var firstChoice: Choice?
    var secondChoice: Choice?
    
    init(story: Story) {
        self.story = story
    }
}

But it is fine for reference types! So the above is cool in a class. We needed the init of course, which only needs a story to go into it when creating an object. 

I was about to stop but am actually going to continue as everything so far seems fine. 

Helper Methods

So this is the if and nested if stuff Pasan has just done - 

extension Page {
    func addChoice(title: String, page: Page) -> Page {
        
        guard firstChoice != nil &&  secondChoice != nil else {
        
        return self
            
        }
            if firstChoice == nil {
                firstChoice = (title, page)
                
            } else {
                    secondChoice = (title, page)
                }
            return page
    }
}

It is so verbose! A switch statement would be better.....

So I was being a bit thick but spotted my error - I needed the , not && between the firstChoice, secondChoice!

extension Page {
    
    func addChoiceWith(title: String, story: Story) -> Page {
        let page = Page(story: story)
        
        return addChoiceWith(title: title, page: page)
    }
    
    func addChoiceWith(title: String, page: Page) -> Page {
        
        
        
        switch (firstChoice, secondChoice) {
        case (.some, .some): return self
        case (.none, .none), (.none, .some):  firstChoice = (title, page)
        case (.some, .none): secondChoice = (title, page)
            
        }
            return page
    }
}

Just going to look over this to make sense of it. 

Right, so you can have multiple methods with the same name. In the case above, the first method is purely to RETURN the second method! That is a new concept - apparently method overloading. I picked that up from the comments. 

Right last bit for today!

Creating An Adventure

*5 minute pause

So we don't want to have to initialise the code every time there's a new page in the app in the view controller. That's NOT the job of the VC!

We want a wrapper struct. So the VC doesn't care where the data has come from as long as it has come in a certain format. 

Right so this is to do with linked lists. I remember these from not so long ago - they are similar to an array. Let's look back at a previous blog...

Extra Reading

Back from this blog - https://www.blogger.com/blogger.g?rinli=1&pli=1&blogID=756758691918297531#editor/target=post;postID=6659913695800272109;onPublishedMenu=allposts;onClosedMenu=allposts;postNum=14;src=postname

This was to do with generics. So the single linked list has a reference just to the next, whereas double link had ref to next and previous. Each item called a node. Nothing else much made sense here. So let's go back to Pasan's current video!

Right so disadvantages with array - when an element is removed, every single element after that one have their index arbitrarily changed.




This is just a visual representation of our data structure! It's not so much a linked list as it is more of a tree, branching out each time.

Our Page class is not just storing data in an array or dictionary.

*SIDE NOTE!

This is not something to overlook  -

https://www.waynewbishop.com

I'm signing up for anything now, but will check this out as a potential avenue, post-Treehouse!

Here we go for the code....second part just copied and pasted!

struct Adventure {
    
    static var story: Page {
    let returnTrip = Page(story: .returnTrip)
    
    let touchDown = returnTrip.addChoiceWith(title: "Stop and Investigate!", story: .touchDown)
    let homeward = returnTrip.addChoiceWith(title: "Continue Home to Earth!", story: .homeward)
    
    let rover = returnTrip.addChoiceWith(title: "Explore the Rover!", story: .rover)
    let crate = returnTrip.addChoiceWith(title: "Open the Crate", story: .crate)
        
    homeward.addChoiceWith(title: "Head back to Mars", page: touchdown)
    let home = homeward.addChoiceWith(title: "Continue Home to Earth", story: .home)
    let cave = rover.addChoiceWith(title: "Explore the Coordinates", story: .cave)
        
    rover.addChoiceWith(title: "Return to Earth", page: home)
    cave.addChoiceWith(title: "Continue towards faint light", story: .droid)
    cave.addChoiceWith(title: "Refill the ship and explore the rover", page: rover)
    crate.addChoiceWith(title: "Explore the Rover", page: rover)
    crate.addChoiceWith(title: "Use the key", story: .monster)

    
    return returnTrip

}

A key point from Pasan is that we have used the STATIC keyword to avoid reference cycles and basically lots of potential confusion!

Quiz time! Wow first question flummoxed me. But it makes sense - an enum with some and none as the cases. Let me rephrase, under the hood, all an optional is is an enum with some and none as the two possible cases.

Question two - can't see the diagram...great! Figured out it must have been doubly linked list.

Finish Time - 19:29 (with all the interruptions, approx 1 hour 30 minutes!)

So I ended up doing too much today! Not a bad thing - I have my lovely big screen so am not feeling headachy at all. Anyway, lots of things picked up today. Let's do a quick summary. 


  • Optionals are essentially enums with two options of .some and .none!
  • Tuples are actually just anonymous structures
  • You can have a function with the same name, with the aim to return the result of that other function (method overloading)
  • The static keyword is used in structs to avoid reference cycle issues and potential problems
  • Linked lists are relevant here as it showed us we needed our own structure for sequencing the adventure 
  • Extensions are a neat way of adding functionality, rather than too much in one custom type!
  • Enums are perfect for having different names for things - in this case chapter titles. Can be applied to so much
  • A wrapper struct is a way of combining various elements to then simplify what goes into the main view controller code
  • Type alias is an awesome way of replacing a tuple with fiddly code and/or labels!

Comments

Popular posts from this blog

*Xcode Project Entry 2* F1 Quiz - part 1

Angela Yu Course Part 10 (up to lesson 112)

Angela Yu Xcode 12 Course - Part 7 (lectures 74 to 79)