Regular Expressions on iOS

I’ve decided to take on the masochistic task of getting my hands dirty with NSRegularExpression. Here are some of my thoughts and findings:

– Regex is voodoo. What’s worse, it’s not even standardized. So all the tutorials on the web are not platform agnostic. I could use a recipe to match the things I’m interested in, but when creating an instance of NSRegularExpression on iOS, it fails as “invalid pattern”.
– Because of this, you WILL become a test driven developer. ūüôā
– Start with a simple regex pattern that detects PARTS of what you’re looking to match, then add complexity. This way you can see what part of your pattern is failing.
– Don’t use the Number Sign # as a matchable character. It is protected but not documented! Use \u0023 instead. e.g. “\\b
– When you map/inspect your NSTextCheckingResult objects, it should have the same number of ranges as you have capture groups. You use these to get more specific about which capture groups were involved in the match. (Provides more granularity/control). The NSTextCheckingResult.range represents the range in the text associated with that one result!
– NSRegularExpression really doesn’t deal well with the hash symbol (sharps).

I ultimately reached a solution, but it never felt entirely ‘correct’ despite finding a way to produce the correct results.

Useful “Finder” methods on NSManagedObject in Swift

I don’t know about you, but CoreData seemed insane to me before I discovered MagicalRecord, back in the days of Mogenerator and Objective-C.

But since Swift 3 has come out, and the tools have improved to support Swift development (remember poor compiler warnings, if not just a “segmentation fault 11” error), I’m finding that I like to work with the Xcode tools again, and forego these old approaches.

My old way of doing things worked very well, and in some ways I miss some aspects of that, but ultimately I quickly (swiftly… cough cough) became a lover of Swift and simply prefer developing in that language.

What I miss most were the “MagicalFinders” categories present in MagicalRecord. ¬†I found quite a concise way to do that however in Swift, and the code looks like this:

import Foundation
import CoreData

@objc public protocol CoreDataFinders {

    /// Because we are doing fetch requests on a data model,
    /// Fetch requests require sort descriptors.
    static func defaultSortDescriptors() -> [NSSortDescriptor]
}

extension CoreDataFinders where Self: NSManagedObject {
    
    public static func findAll(with predicate: NSPredicate?, context: NSManagedObjectContext) -> [Self] {
        
        let fetchRequest: NSFetchRequest = NSFetchRequest(entityName: Self.entity().name!)
        
        let predicate = predicate
        
        fetchRequest.predicate = predicate
        fetchRequest.sortDescriptors = self.defaultSortDescriptors()
        
        do {
            let results = try context.fetch(fetchRequest)
            return results
        } catch {
            if predicate != nil {
                print("Failed to fetch objects with predicate:\(predicate!.description) error:\(error)")
            } else {
                print("Failed to fetch objects with no predicate.  error:\(error)")
            }
        }
        return []
    }
    
    public static func findFirst(with predicate: NSPredicate?, context: NSManagedObjectContext) -> Self? {
        
        let fetchRequest: NSFetchRequest = NSFetchRequest(entityName: Self.entity().name!)
        
        let predicate = predicate
        
        fetchRequest.predicate = predicate
        fetchRequest.sortDescriptors = self.defaultSortDescriptors()
        fetchRequest.fetchLimit = 1
        
        do {
            let results = try context.fetch(fetchRequest)
            return results.first
        } catch {
            if predicate != nil {
                print("Failed to fetch objects with predicate:\(predicate!.description) error:\(error)")
            } else {
                print("Failed to fetch objects with no predicate.  error:\(error)")
            }
            
        }
        return nil
    }
}

And then you can add these to any object by either making a new baseclass in your app that subclasses NSManagedObject, or you just declare protocol support in your class definition and then these methods are added:

import Foundation
import CoreData

@objc(RecentItem)
class RecentItem: NSManagedObject, CoreDataFinders {
  static func defaultSortDescriptors() -> [NSSortDescriptor] {
    return [NSSortDescriptor(key: #keyPath(RecentItem.lastViewed), ascending: false)]
  }
  // ...
}

You can see here that you can extend this approach to pass in your own sort descriptors or limit fetch sizes, etc. This should be enough to get you started! The idea is that you can write the code once and have it apply to all instances of NSManagedObject on an opt-in basis.

Developing for iCloud sucks

iCloud is the thorn in Apple’s side. ¬†They have been trying to get this right forever. ¬†Maybe it works now from an end-user perspective, but as a developer, what a rough, confusing implementation.

I have to say, when you work with the Dropbox API, it is intuitive, it is easy, it is straightforward. Perhaps you have to write a lot of boilerplate code, but then again, do you?  It manages files.  This name, that path, that revision number, that modifiedDate.  You sort out the rest.  How hard can that be?

I’m currently writing a sync engine that allows users to decide which cloud service they want to use to backup their data. ¬†So of course it would make sense to have one common API that wraps the various services.

It went so smoothly with Dropbox. ¬†The only difficulty I had was realizing that the serialization of date strings sometimes results in small differences in the Date that emerges, meaning I had to write a .isTheSameAs(other: Date) method, which checks to see if they are within X seconds of each other, then call those ‘the same’.

Then I moved on to iCloud. ¬†What a clusterf‚ÄĘck. ¬†Talk about over-engineering and complete inflexibility. ¬†I just want a list of files that are in the cloud. ¬†No, Apple has to distinguish whether you have them locally or not, and gives them a different URL. ¬†And all sorts of other weird stuff.

So I tried to find a framework that makes iCloud a little more user-friendly, called iCloudDocumentSync which I found to be pretty straightforward, all things considered. ¬†And yet, it’s still a pain. ¬†Because iCloud uses multiple URLs to represent the same document. ¬†In the end, I have to sync the entire iCloud folder’s contents before I can start working with these with a common URL. ¬†(Sure I could extract the file name I need). ¬†Moreover, iCloud uses a thread to open each document, so if I want to batch download a lot of data, suddenly I have a thread explosion. ¬†Now I have to deal with managing that.

All in all it’s just been a pain to work with it. ¬†It seems opaque in its verbosity. ¬†Meaning, the person who talks a lot doesn’t get listened to and understood. ¬†There are so many callbacks and all sorts of weird things going on, it’s very annoying. ¬†Just because they’re trying to save the developer time, they’ve implemented something weird and unwieldy if you don’t use it according to their use case. ¬†I personally just use a UIDocument as a means to save data. ¬†I don’t work with UIDocuments because my app’s data model uses the data, but not the file. ¬†This just seems silly with iCloud.

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.