Raywenderlich.com Table Views Course Part 1

So you could say, reorientation complete! Having gone through the Coursera stuff (must cancel that subscription actually) I feel like I've got most of the essentials again. Of course there are elements that I haven't gone over e.g. protocols but all in good time! I'm proud because in a couple of weeks, I've managed to make two mini apps (very, very basic) that actually work! Most importantly, I'm back coding and will make time, even when back at work. 

Another idea is to start mapping out on A3 paper some of the key content from each course. It would save as a useful memory aid - on here, the information is gone once the blog is complete. This is more just an overall record and to help make sense of something. So one A3 paper per course, and one overall A3 paper (maybe more, in time) to just track what I'm doing VISUALLY. We'll see! And after all the Coursera  hype, I'm back to raywenderlich.com! Starting with table views...

This is from Catie Catterwaul, an instructor who I've thought highly of in previous courses. The first project is in Storyboards. 

I like the concept of the project - a digital library! I love reading and use the GoodReads app. So this is cool! So far, I have three properties: title, author and image (of the book). 

OK.... a lot to digest in this first part before I have a break. There are basically two functions that HAVE to be in place - that follow the protocol for TableViews! These are 1) number of rows in section and 2) cell for row at index path. 

For 1) you can just return an Int. You could use any smallish number but better to use the count property if accessing an actual data source. 2) is much harder! After putting in Catie's custom swift file which has a database of books and library codes, here is the code for the two necessary functions....

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        return Library.books.count

    }

    

    

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "BookCell", for: indexPath)

        let book = Library.books[indexPath.row]

        

        cell.textLabel?.text = book.title

        cell.imageView?.image = book.image

        return cell

    }

Let's break that down... the 'cell' constant' is what is eventually returned. It's a local constant for this particular function. In that cell, we apply the 'dequeueResuableCell' method, so that we have the right number of cells shown at a time - so it's not overloaded. 

The cell constant is just the name of what I called the cell in the TVC ("BookCell") and indexPath has to be in there. 

The book constant uses Catie's custom code to access those in the Library and accesses the row from there (not entirely sure about that yet). 

Then text and an image are chosen for cell - both accessed from the local constant of book, from that database. 

Phew!

Honestly, great stuff so far - really, really clear however complex. Quick break!

Back!

Cool tip - to get aspect ratio of 1:1, a quick way is to control and drag the object on itself, then old down option then aspect ratio 1:1 comes up - click that! Some other useful tips from Catie - clicking and dragging as before but just onto the canvas, selecting centre vertically/horizontally/centre... then editing that to a multiplier of 0.5. Looks good! And then the 'reload' frames' button. That is what I need to use regularly!


OK the segue bit is so good! It is one segue to go back and forward, it gives the back button... This is a LOT better than Mark's one and my Buffy one. That could simplify things massively, in fact it easily could! That is one 'consolidation' project I will focus on. 

OK @IBSegueAction is needed. Again, protocols must be followed...

Wowzers, a ViewController coded from scratch? Yep!

import UIKit


class DetailViewController: UIViewController {

    

    let book: Book

    

    @IBOutlet var titleName: UILabel!

    @IBOutlet var authorName: UILabel!

    @IBOutlet var imageView: UIImageView!

    

  

    

  

    

    override func viewDidLoad() {

        super.viewDidLoad()

        imageView.image = book.image

        titleName.text = book.title

        authorName.text = book.author

    }

    

    required init?(coder: NSCoder) {

          fatalError("This should never be called!!")

      }

    

    init?(coder: NSCoder, book: Book) {

        self.book = book

        super.init(coder: coder)

      }

}


I pretty much get this but let's break it down. An instance of 'book' from the Book struct is needed. The three main outlets i.e. labels and image view are created. In the usual viewDidLoad bit, is where the info from book (the 3 properties) is then passed into. Fine so far. 


The init bit is confusing but that's OK. This is a customVC so I guess that's why this bit seems newer. Required one should never actually get called but the other init is where the book info and coder is actually used. I think!


A weird, cool way of then just click and dragging these - from the connections inspector (far right button) to the relevant label/image. Nice!


Spotted a mistake but opened Catie's code file and seen what happened - Library keyword missing. Also, I also did the wrong segue, undid it but never actually removed it from the connections bit. So solved both issues, nice!


OK, time for another break. Back for the rest of this section (1 of 3)!


First thing is the 'Library' file has been updated with two new functions and an extension - 


static func saveImage(_ image: UIImage, forBook book: Book) {

      let imageURL = FileManager.documentDirectoryURL.appendingPathComponent(book.title)

      if let jpgData = image.jpegData(compressionQuality: 0.7) {

        try? jpgData.write(to: imageURL, options: .atomicWrite)

      }

    }

    

static func loadImage(forBook book: Book) -> UIImage? {

      let imageURL = FileManager.documentDirectoryURL.appendingPathComponent(book.title)

      return UIImage(contentsOfFile: imageURL.path)

    }

  }



  extension FileManager {

    static var documentDirectoryURL: URL {

      return `default`.urls(for: .documentDirectory, in: .userDomainMask)[0]

    }

  }


I'll come to these! OK, these bits of code I can't break down into detail as I honestly don't understand them, for now. But that's fine - I don't ned to know the inner workings of them. They allow images to be saved and loaded and the extension is to allow that to happen. That's all I can say!


Other bits of code for the 'Reload Data' part are complex - here is the ImagePicker stuff...


extension DetailViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {


func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

        guard let selectedImage = info[.editedImage] as? UIImage else { return }

        imageView.image = selectedImage

        Library.saveImage(selectedImage, forBook: book)

        dismiss(animated: true)

    }

}


This is all typically complex for using anything UI with the 'Storyboard' Swift - I've seen that enough recently! The above is a specific function 'imagePickerController', which allows the user to select a photo from their library. Again, a lot of code, but I don't need to memorise it! It's all in an extension of the DetailViewController, which also conforms to two delegates.  


Other bits and pieces needed - a property (privacy of camera) added to the p-list, something else onto the viewDidAppear... Anyway, when I try to replicate and apply the code for my consolidation after this (I've decided, Harry Potter!), then it will make more sense. All good for now, in terms of what I need to know!


So, for the A3 paper, I have filled most of a page, with key notes. I will keep, refer to and display when needed! On the other A3 bits, with overall for rw.com, it's the first one added, just the name and date started. Cool!



Comments

Popular posts from this blog

Coursera Introduction to Programming in Swift - Part 4

Coursera - Intro to IOS Development Part 1