cs193p – Lecture #9 Scroll View and Multithreading

By Pearson Scott Foresman [Public domain], via Wikimedia Commons

Please note, this blog entry is from a previous course. You might want to check out the current one.

The lecture starts with additional information on how to control the appearance of a view in different size classes and how to inspect constraints in various size classes.

Scroll Views

Adding sub views to a scroll view works similar like adding views to any other view. The only important difference is to define the content size of the scroll view:

scrollView.contentSize = CGSize(width: 3000, height: 2000)
logo.frame = CGRect(x: 2700, y: 50, width: 120, height: 180)
aerial.frame = CGRect(x: 150, y: 200, width: 2500, height: 1600)

Various methods allow to detect which part of the scroll view is currently visible, to scroll programmatically, or to control its properties:

let upperLeftOfVisible: CGPoint = scrollView.contentOffset
let visibleRect: CGRect = aerial.convertRect(scrollView.bounds, fromView: scrollView)

func scrollRectToVisible(CGRect, animated: Bool)

To allow zooming the limits of the zoom scale need to be set, and a delegate defining the view to zoom. It’s also possible to zoom programmatically.

scrollView.minimumZoomScale = 0.5 // half its normal size 
scrollView.maximumZoomScale = 2.0 // twice its normal size

func viewForZoomingInScrollView(sender: UIScrollView) -> UIView

var zoomScale: CGFloat
func setZoomScale(CGFloat, animated: Bool)
func zoomToRect(CGRect, animated: Bool)


Closures encapsulate pieces of code and capture variables of the surrounding context. To avoid referencing loops, weak references or unowning is necessary e.g.:

class Foo {
      var action: () -> Void = { }
      func show(value: Int) { println(“\(value)”) }
      func setupMyAction() {
          var x: Int = 0
          action = { [unowned self] in
      func doMyAction10times() { for i in 1...10 { action() } }


To avoid stalling user interaction, lengthy tasks should be performed on other queues than the main queue. Only to report back to the user interface it is necessary to return to the main queue.

dispatch_async(notTheMainQueue) {
      // do something that might block or takes a while
      dispatch_async(dispatch_get_main_queue()) {
            // call UI functions with the results of the above

Depending on the task other queues have different priorities:

QOS_CLASS_USER_INTERACTIVE // quick and high priority
QOS_CLASS_USER_INITIATED   // high priority, might take time
QOS_CLASS_UTILITY          // long running
QOS_CLASS_BACKGROUND       // user not concerned

let qos = Int(<one of the above>.value) 
let queue = dispatch_get_global_queue(qos, 0)

Tasks might even be dispatched to other queues to be run in the future …

… and there might be some methods which run be default on other queues.

The lecture and its slides are available via iTunes named “9. Scroll View and Multithreading”. The code for the cassini demo is available on GitHub and at Stanford.


Flattr this!

5 thoughts on “cs193p – Lecture #9 Scroll View and Multithreading”

      1. That is correct, I am using latest version of Swift. However I still think there is something wrong with the logic, I decided to test because it doesn’t make sense to me. Please can you try?

Leave a Reply

Your email address will not be published. Required fields are marked *