• How To Bild An App Without Interface Builder - Part 1: Setup

    Back in the days Apple shipped an empty iOS project template with Xcode. With Xcode 5 they removed it to promote the use of storyboards. When you now create an iOS project you always get a storyboard. In this post I'll show you how to remove the storyboard and how to change the AppDelegate to load a view controller using code. A similar approach can also be used to load view controllers with xibs.

    Note: I'm using Xcode 7 beta 4. But what is shown here should work in Xcode 6 as well.

    Open Xcode and create a new project (File/New/Project...), select the iOS/Single View Application template and click Next. Name the project (I'll use Birthdays as a working title), select Swift and check Include Unit Tests. Later we will also add UI tests. But at the beginning we want to have fast tests.

    Screen Shot 2015-07-24 at 17.58.19

    Click Next. Select a place on your hard drive to store the project and click Create.

    Read more...

  • Implementing SequenceType

    Sometimes you have a struct/class that holds some kind of sequence and you would like to iterate over it with for ... in .... In Swift the struct/class has to conform to SequenceType to enable this iteration.

    Let’s say you have a simple struct to hold domains:

    struct Domains {
      let names: [String]
      let tld: String
    }

    To conform to SequenceType the struct needs to implement the method:

    func generate() -> Self.Generator

    and the Generator is of type GeneratorType. Ok, let’s start with the generator.

    Read more...

  • Using Guard In Unit Tests

    Here is the problem: Sometimes you want to test an element that could be nil. For example, I recently wanted to test if a view controller has a right bar button item with a given target. This could be done like this:

    func testViewController_HasAddButtonInNavigationBar() {
      let _ = viewController.view
      
      XCTAssertNotNil(viewController.navigationController)
      XCTAssertNotNil(viewController.navigationItem.rightBarButtonItem)
      let addBarButton = viewController.navigationItem.rightBarButtonItem!
      let target = addBarButton.target
      XCTAssertEqual(target as! TimerTableViewController, viewController, "The view controller should be the target of the right bar button")
    }

    The problem with this code is, that if there is no right bar button item the test execution crashes. Let’s make it kind of better:

    func testViewController_HasAddButtonInNavigationBar() {
      let _ = viewController.view
      
      if let _ = viewController.navigationController {
        XCTAssertNotNil(viewController.navigationItem.rightBarButtonItem)
        if let addBarButton = viewController.navigationItem.rightBarButtonItem {
          let target = addBarButton.target
          XCTAssertEqual(target as! TimerTableViewController, viewController, "The view controller should be the target of the right bar button")
        }
      } else {
        XCTAssertFalse(true)
      }
    }

    Uhhg… Now it doesn’t crash but it’s really ugly. Here comes the rescue with guard:

    Read more...

  • How To Bild An App Without Interface Builder - Part 0

    If you are using Interface Building and you think it's kind of magic what Interface Builder and storyboards do to bring your app to life, then this blog-series is for you. We will build an app from zero to App Store without using Interface Builder when possible. For the Watch app we'll need to have a storyboard because at the moment they are needed when building Watch apps.

    About the app:

    • Birthday reminder
    • Today extension
    • Watch App
    • Test Driven Development
    • No storyboard except for the watch App
    • Only one xib for the launch screen
    • Open source
    • Swift 2.0
    • Light table view controllers
    • PaintCode for the custom table view cells

    About this series:

    • I'll write as I go. This means we will most probably find ourselves in a dead end sometimes and need to rewrite parts of the app.
    • I'm not an expert in Test Driven Development. This means the way I use it might be strange or even wrong. If you find problems with my code or my tests, please leave a comment or ping me at Twitter or App.net.
    • I'll try to publish a blog post in the series every Monday. Let's hope I succeed. :)
    • The code of the app will be open source. If you want to put your own version into the store, feel free to do so. The code will be released under MIT license.

    List of posts:

    If you enjoyed this post, then make sure you subscribe to my feed.

    Read more...

  • Mind-Blown By Swift's Type System

    Swift's type system is a source of frustration and not few developer state that it solves a problem nobody had. In my opinion it's useful mainly for beginners. It helps to find misunderstandings of Cocoa APIs and other people's code early. But I also think that the influence on the number of bad bugs in shipped apps is low. Most of the prevented errors are so obvious that they get caught during debug runs.

    But a few days ago I stubbled across a feature of Swift's type system that blew my mind.

    You sure have seen already this kind of type inference:

    func aNumber() -> Int { return 1 }
    func aNumber() -> Double { return 2.0 }
    
    let a: Int = aNumber() // -> 1
    let b: Double = aNumber() // -> 2

    The constant a is declared to be of type Int and therefore the first version of aNumber() is called. In the case of a Double on the left side of the assignment (b) the second version is called.

    So far so good. Let's take this to the next level. UIView has an initializer that takes a CGRect. This makes the following type inference possible:

    var coloredView = UIView(frame: .zeroRect)

    So the compiler already knows that the frame only can be a CGRect and accesses the corresponding property zeroRect of CGRect.

    This is already kind of cool. But there is more. The type system can handle code like this:

    coloredView.backgroundColor = .yellowColor()

    And this blew my mind. It make the code easier to read an removes unnecessary cruft. But it's also kind of obvious because it's kind of the same as the previous example in the initializer of UIView.

    And then I became high-spirited and tried this:

    var layoutConstraints = [NSLayoutConstraint]()
    layoutConstraints += .constraintsWithVisualFormat("|-[stackView]-|", options: [], metrics: nil, views: views)

    (Note that NSLayoutConstraint is missing in front of constraintsWithVisualFormat(...).)

    Unfortunately it doesn't work. To find out what the problem is I changed the code to:

    let theConstraints: [NSLayoutConstraint] = .constraintsWithVisualFormat("|-[stackView]-|", options: [], metrics: nil, views: views)

    and got the error:

    '[NSLayoutConstraint].Type' does not have a member named 'constraintsWithVisualFormat'

    This means the compiler uses the type on the left side to find a method with the signature from the right side of the assignment. This obviously doesn't work and I'm not sure if it should work. It would make my code more compact but at some point more compact becomes to compact.

    If you enjoyed this post, then make sure you subscribe to my feed.

    Read more...

  • Size Classes Under The Hood

    I wondered what happens when a view is not present in a specific size class in a storyboard because I want to mimic this behavior in code.

    I've created a test project and added two labels to the storyboard scene. labelOne is in the size classes Any-Any. labelTwo is only in the size class Regular-Compact.

    To see what's going on I added outlets and the following print commands in viewDidLoad:

    print("(labelOne.hidden) (labelOne.alpha) (labelOne.superview)")
    print("(labelTwo.hidden) (labelTwo.alpha) (labelTwo.superview)")

    The debug output is:

    false 1.0 Optional(<UIView: 0x796e3740; frame = (0 0; 320 480); autoresize = W+H; layer = <CALayer: 0x796e3910>>)
    false 1.0 nil

    This means, the labelTwo isn't shown when running for example on iPhone 4s because it is not added to the view. But the label is not nil even though it's a weak reference. I assume the reason behind that is that the storyboard holds a reference to the label.

    I will try to mimic this behavior when creating code that uses size classes.

    Read more...

  • Table View Footer In Plain Table View

    A few days ago I learned a neat trick. You maybe familiar with the look of a plain table view on iOS:

    Simulator Screen Shot 29.06.2015 21.46.49

    Even though there are only two cells in the table view, there are all those lines and it looks like there are many more empty cells. Sometimes you don't want those empty cells. You could use a grouped table view but this looks different especially when you have section headers.

    The trick is to add a table footer view:

    tableView.tableFooterView = UIView(frame: CGRect.zeroRect)
    

    As you can see the footer view has a frame of zeroRect which is the same as CGRectMake(0, 0, 0, 0) . The result looks like this:

    Simulator Screen Shot 29.06.2015 22.04.30

    You can find the trivial code on github.

    Read more...

  • Playing With UIStackView

    iOS 9 will bring UIStackView and with it will make creating adaptive layout easier than ever.

    This is important because with the new multitasking on iPad you want to make sure that your app can handle all possible different screen sizes.

    In the past many developer had difficulties to get their head around Auto Layout. Many third party libraries tried to make the creation of layout constraints in code easier. Several books have been written about Auto Layout.

    Apple addressed this with the introduction of a new API to create layout constrains in code and UIStackView. Using UIStackView you just set a few properties and add views you want to be arranged by the stack view. Under the hood UIStackView adds Auto Layout constraints to the arranged views according to the property values you have set.

    It arranges its subview vertically or horizontally. You can nest UIStackViews to achieve many different layouts. In addition you can add additional constraints to the views. Changes to the properties of the stack view and its subviews are animated by default.

    Sounds great, doesn't it? I love Auto Layout and therefore was exited to try what UIStackView brings to the table. As I'm not a fan of Storyboards I created a Playground to experiment with UIStackViews in code.

    Examples

    Here are the different layouts I've created. More to come (suggestions welcome!):

    iOS Calculator

    Screen Shot 2015-06-26 at 16.36.17

    A Profile View

    Screen Shot 2015-06-26 at 11.16.32

    A Tweet/Post

    Screen Shot 2015-06-26 at 11.34.54

    iOS Mail Inbox

    Screen Shot 2015-06-27 at 17.58.13

    Some Tipps

    1. Don't forget to disable translatesAutoresizingMaskIntoConstraints when you position you stack view using Auto Layout.
    2. Views arranged by a stack view have automatically translatesAutoresizingMaskIntoConstraints disabled.
    3. If your subviews are bigger than they should be, try to set the alignment to something else than .Fill (which is the default).
    4. Spacing can be negative (see the Profile example) but I did not manage to make a spacing that is smaller that the negative of the width of the smaller subview. (I need to experiment with the distribution parameter a bit for this case.)
    5. If you add constraints to an arranged view, try to think what constraints the stack view implicitly added and don't fight those.
    6. Sometimes you need to put a stack view into a view which itself is part of a stack view.
    7. Stack views can have subviews that are not arranged (i.e. don't get implicit constrains).
    8. If you want to use stack views or the new Auto Layout API in a Playground put the code in a if #available(iOS 9, *) { } condition. Otherwise the Playground won't execute.

    If you want to experiment yourself, the Playground is on github.

    Read more...

  • Open Sourcing Fojusi

    Right after Swift was announced I read a post on a well known website that they are searching for people who want to create video tutorials for them. I volunteered and started to implement a demo project for the video tutorial, a timer app.

    I made the videos and wrote the people from the blog that I'm finished and asked where I should send the video to. I never heard from them again.

    So I decided to build a complete app from the demo project. Few days later I had the first version of Fojusi finished and put it in the App Store.

    Then came the October Special Event. In the keynote Hair Force One showed a slide with a apps already written in Swift (https://youtu.be/sBfvJn-fpnc?t=16m5s). And I nearly fall from the couch as I realized that Fojusi was on that slide (bottom right corner).

    Screen Shot 2015-06-25 at 22.45.48

    A few days ago I decided to make Fojusi open source. Feel free to use the code to make you own timer app to be on one of the slides in the next keynote.

    Future plans

    When I find time I want to add watch support to Fojusi. But I want to use watchOS 2 for this. So I need to watch some WWDC videos first.

    Ping me at Twitter or App.net if you have comments about this post or Fojusi.

    Read more...

  • Small Swiftly Features I Keep Forgetting - Part 1

    I'm reading the Apple Swift book once again. This time the prerelease version for Swift 2.0 and I rediscover things from earlier releases of Swift I had forgotten. So, ignore this post. This is just a reference for the future me. :)

    ## Swift Tour
    Functions can take a variable number of arguments.

    func sumOf(numbers: Int...) -> Int {
      return numbers.reduce(0, combine: +)
    }
    sumOf(1,2,3)

    You can provide an explicit name in parentheses after set in a setter.

    struct Person {
      var name: String {
        get { return self.name }
        set(theNewName) { print("the new name is (theNewName)") }
      }
    }
    var person = Person()
    person.name = "Dominik"

    ## The Basics
    You can access the minimun and maximum values of each integer type with.

    let minValue = UInt8.min
    let maxValue = UInt8.max

    ## Strings and Characters
    Find out whether a `String` value is empty by checking its Boolean `isEmpty` property.

    let emptyString = ""
    if emptyString.isEmpty {
      print("It's really empty")
    }
    

    ## Collection Types
    Append an array of one or more compatible items with the addition assignement operator (`+=`).

    var shoppingList = ["Soy Milk", "Bread"]
    shoppingList += ["Apples", "Bananas", "Coffee", "Creme"]

    You can also use subscript syntax to change a range of values at once, even if the replacement set of values has a different length than the range you are replacing.

    shoppingList[4...5] = ["Bananas", "Bananas", "More Bananas"]
    shoppingList

    If you need the integer index of each item as well as its value, use the `enumerate()` method to interate over the array instead.

    for (index, value) in shoppingList.enumerate() {
      print("(index): (value)")
    }

    You can also initialize a set with an array literal, as shorthand way to write one or more values as a set collection.

    var favoriteGenres: Set = ["Rock", "Indie", "Sing and Songwriter"]

    Set: intersect(_:), intersect(_:), union(_:) and subtract(_:) .

    let oddDigits: Set = [1, 3, 5, 7, 9]
    let evenDigits: Set = [0, 2, 4, 6, 8]
    let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]
    oddDigits.union(evenDigits).sort()
    oddDigits.intersect(evenDigits).sort()
    oddDigits.subtract(singleDigitPrimeNumbers).sort()
    oddDigits.exclusiveOr(singleDigitPrimeNumbers).sort()

    Did you find something one should mention here? Let me know.

    Read more...



subscribe via RSS