Autolayout and Self-sizing UITableViewCell

I’m not going to lie.  Autolayout is a massive pain.  But.  Ultimately it’s very powerful and you’re best to just go through the pain and learn it.

Even so, you should also get a bit familiar with it, then learn about the concept of self-sizing table view cells.  It’s quite important.  Basically, as long as there is a clearly defined way for a UITableViewCell to determine its own height via the auto-layout constraints, dynamic table view cells are pretty easy.

Unfortunately, there is a lot to learn:

This series

Then this

or even Apple

Quick Reference:

How to make sure a UITableViewCell autosizes when you have a label that you want to wrap around onto multiple lines.

1. Pin the Label at top left, bottom, right.

2. Edit the right constraint to be “Greater than or Equal to”, and then set the constant to be the right-most you want to allow that (probably view margin).

3. Set that right-most constraint’s priority to 750 (high), then set (on the Label!) it’s content compression resistance priority to 749.

Should be fine now.

Alamofire and nostalgic feelings for AFNetworking

So, in the Swift world, I presume a lot of people prefer to remain “Swifty”.  That is, why would you opt for old Objective-C libraries?  Out with the old, in with the new!

So, we adopt Alamofire.  Is it just me, or is this library a bit unwieldy?   I think it has a lot to do with Swift shorthand and often not knowing just what types are actually being passed around, especially given autocomplete.

On top of that, just when you get your head around a specific release, they make a new major release, breaking old APIs.  And if I’m going to have to keep updating my code to stay current because “out with the old, in with the new”, why don’t I just stay with AFNetworking?  I mean come on.  It’s networking.  For the mostpart it’s just “give me that data at that URL.  Here’s my auth info.”  Done.  Or “here’s some data for you.  Here’s my auth info.”  Done.

Anyway, it’s a rant.  I just don’t find Alamofire all that sexy.  It reminds me of dealing with civil servants.  The creators imagined this bureaucratic utopia that functions perfectly as long as everyone understands it.  Furthermore, we must not only understand it, but are fully on board with its vision.  Meanwhile, we the people are busy trying to write our own apps, and couldn’t really care less.  We just want to get data and post data and not have to deal with too much crap in the middle.

(Go ahead, snarky programmer.  Now tell me off, tell me to just use this, that, or the other.  Reject my feedback.  It’s fine.  All I’m saying is that AFNetworking seemed a lot easier to use.)

Today was the first day that Test Driven Development actually justified its existence

I’ve been making apps since iOS 2.2.  People tell me I’m good at it.  Meh.  There’s always a bigger fish.  I love what I do, so chances are I’m not horrible at what I do.

Today was the first day where I used Test Driven Development to actually develop code.  Don’t get me wrong; it’s not like I don’t write unit tests.  I do.  But what I’m referring to right now is where you actually are given the start and passing conditions of a test before there is any code written at all.  In my field of work, this never happens.  The design is ALWAYS a moving target.  Nothing in the startup world is ever known in advance, so although you could write unit tests, it doesn’t always make sense.

I’ve recently been working on the implementation of the rules of Canadian Ice Hockey.  (Don’t ask.)  The sport itself seems pretty straightforward.  Put the puck in the net.  Goal.  Increase Score.  No way!  There are a lot of complicated rules surrounding penalties, but thankfully there is a referee’s handbook that goes over all the complicated scenarios and tells you what the result should be.

Perfect for TDD.  I literally wrote all the unit tests before I wrote the code that would produce the expected results.  I love it because I have to be honest; the solver code I wrote just “feels bad”.  I’m not even certain how parts of it work, and I only wrote it this past week.

What unit tests tell me is: It doesn’t matter!  As long as the tests pass, the code does what it’s supposed to do.  Very satisfying.

 

What I miss about Objective-C

Don’t get me wrong; I love Swift and it’s my preferred language.  It really didn’t take long to love it.

That being said, I really miss the idea of protected and private declarations, and creating Category Headers to expose private API’s.

It’s like giving a class “special permission” to interact with the private API’s of a different class, if there are a few classes that operate more closely, but still limiting the exposure of some properties to objects that aren’t coupled as tightly.

In Swift you just expose them all and write comments I guess.  Perhaps I’ll figure that out when I become more experienced with Swift.

DataSource object for UITableView / UICollectionView in Swift with Core Data

It’s amazing how quickly I now have become a part of the Swift Fan Club.  I recently worked on some old Objective-C code of mine and was amazed how quickly one learns to stop typing semi-colons.  🙂

Today’s post is all about a pattern I use more often in my projects, and it’s one that prefers composition over inheritance.  All that really means in this case is that on any UITableViewController (or similarly, UICollectionViewController), I prefer to create separate Data Source objects that keep all that code separate from the View Controller itself.  (I personally don’t find that MVC stands for Massive View Controller if you don’t let it.)

The issue here is that I pretty much don’t do projects any more without using Core Data.  It is the best solution in my opinion because of the code you oftentimes *don’t* have to write.  Also, with NSFetchedResultsController, I like how you can further separate your data layer (think Networking and importing) from you View Controllers.  View Controllers concern themselves with *what* they want to display, and not with how it is acquired.

Anyway, the strictly typed language of Swift sometimes makes old approaches not straightforward, and I would like to share what I determined today.  It will become a staple in my future Swift projects.

I create a DataSource class that takes a generic type, so that this generic type can be used for Core Data related activities.  By default, a NSFetchedResultsController also takes a generic type of NSFetchRequestResult. But sometimes that is simply not enough. More on this later. To even make a Generic Data source, we have:

class BasicFetchedResultsDataSource: NSObject, NSFetchedResultsControllerDelegate where T:NSManagedObject {
    
    let managedObjectContext: NSManagedObjectContext!
    let tableView: UITableView!
    
    init(context: NSManagedObjectContext!, tableView: UITableView!) {
        
        self.managedObjectContext = context
        self.tableView = tableView
    }
    
    private var _fetchedResultsController: NSFetchedResultsController? = nil
    var fetchedResultsController: NSFetchedResultsController {
        
        if _fetchedResultsController != nil {
            return _fetchedResultsController!
        }
        
        let request = T.fetchRequest()
        request.predicate = self.searchPredicateForFetchRequest
        request.sortDescriptors = self.sortDescriptorsForFetchRequest
        let controller = NSFetchedResultsController(fetchRequest: request as! NSFetchRequest,
                                                    managedObjectContext: self.managedObjectContext,
                                                    sectionNameKeyPath: self.sectionNameKeyPath,
                                                    cacheName: self.resultsControllerCacheName)
        
        controller.delegate = self
        _fetchedResultsController = controller
        return _fetchedResultsController!
    }
    
    
    func updateRequestAndFetch() throws {
        
        self.fetchedResultsController.fetchRequest.predicate = self.searchPredicateForFetchRequest
        self.fetchedResultsController.fetchRequest.sortDescriptors = self.sortDescriptorsForFetchRequest
        
        do {
            try self.fetchedResultsController.performFetch()
            
            self.tableView.reloadData()
        }
        catch {
            throw error
        }
    }
    
    // allows your subclass to override and change this
    var sectionNameKeyPath: String? {
        return nil
    }
    
    // allows your subclass to override and change this
    var resultsControllerCacheName: String? {
        return nil
    }
    
    // allows your subclass to override and change this according to state
    var sortDescriptorsForFetchRequest: [NSSortDescriptor]! {
        return []
    }
    
    // allows your subclass to override and change this according to state
    var searchPredicateForFetchRequest: NSPredicate? {
        return nil
    }
    
    // ... Typical NSFetchedResultsController and UITableViewDataSource code here.
}

That’s it for the basics, but what if my data model is a bit more interesting? In my current project I want my data to be sortable, filterable, searchable, and possibly groupable.

So I define the following:

import CoreData
@objc protocol Sortable: NSFetchRequestResult {
    static func defaultSortDescriptors() -> [NSSortDescriptor]!
}

@objc protocol Groupable: NSFetchRequestResult {
    var groupIndex: String! { get }
}

@objc protocol RelationshipFilterable: NSFetchRequestResult {
    static func relationshipFilterPredicate(for constraintObject:NSManagedObject?) -> NSPredicate?
}

@objc protocol TextSearchable: NSFetchRequestResult {
    static func searchPredicate(for searchTerm:String?) -> NSPredicate?
}

@objc protocol MyGenericDataObject: Sortable, Groupable, RelationshipFilterable, TextSearchable {
    // combines them
}

Then the cool stuff. Subclass the Basic view controller above:

class GenericFetchedResultsDataSource: BasicFetchedResultsDataSource where T:NSManagedObject {
    
    let allowsGrouping: Bool
    let allowsTextSearching: Bool
    
    override init(context: NSManagedObjectContext!, tableView: UITableView!) {
        self.allowsGrouping = true
        self.allowsTextSearching = true
        super.init(context: context, tableView: tableView)
    }
    
    var currentSearchTerm: String? {
        didSet {
            if self.allowsTextSearching {
                do {
                    try self.updateRequestAndFetch()
                }
                catch {
                    print("Fetch Error: \(error)")
                }
            }
        }
    }
    
    override var sectionNameKeyPath: String? {
        return self.allowsGrouping ? #keyPath(MyGenericDataObject.groupIndex) : nil
    }
    
    override var resultsControllerCacheName: String? {
        return nil
    }
    
    override var sortDescriptorsForFetchRequest: [NSSortDescriptor]! {
        return T.defaultSortDescriptors()
    }
    
    override var searchPredicateForFetchRequest: NSPredicate? {
        return self.allowsTextSearching ? T.searchPredicate(for: self.currentSearchTerm) : nil
    }
}

And that’s how you can work with generics and their subclasses. It’s why protocol oriented programming and swift go together nicely!

How Swiftly I began to love Swift…

So, my last post was a little nasty.  Written like a conservative populist, which politically I’m not, but I admit I had my reservations about learning Swift then, and I stand by that opinion at that time.  I’ll be brief this time.   I’ve now had a chance to really do some work with Swift and I have to say overall I quite like it, and never expected that to happen so quickly.  Why the change of heart, you might ask?

  • I guess I don’t like learning from books, but I like learning by doing.  I find a lot of tutorials out there on the internet kind of superficial and boring.  I joined a project where there was already enough Swift code but not too much.  I had the opportunity to contribute based on some code I could already work from.
  • I really do like a lot of the features, such as enums (and being able to use string types)
  • The syntax is pretty good.  It does make for readable, type-safe code.
  • I’m surprised at how quickly one can just start writing useful code
  • Since Swift 3, there really is no reason to say no to it.  Previously it all felt “too new” and not finished.  The compiler warnings were a total disaster. For a strictly typed language, having poor compiler warnings was the most discouraging aspect to it. (Hence the rant about German bureaucrats who aren’t helpful but just say no)
  • I’m sure other reasons here as well

Now, it’s not like I’ve become blindly religious.  Sometimes I don’t like to the strictly typed language, but I suspect my frustration comes from the typical approach of “well, in Objective-C, I could just…” and not yet knowing the equivalent approach in Swift.

But all in all, I think it’s pretty easy to get up and running and to start writing Swift code that is useful and readable.  I’ve seen some library code that tells me I still have a lot to learn, but for now I think it’s kind of a “no turning back” situation.

I’ve already basically done all the types of things I’ve done in objective-C, and find that I really didn’t use KVO that much anymore anyway, so I don’t miss it.

I thought I’d just round off that last angry post with something nice.