Swift Regex Deep Dive
iOS MacOur introductory guide to Swift Regex. Learn regular expressions in Swift including RegexBuilder examples and strongly-typed captures.
One of the directions Apple is taking in Objective C that I’ve come to really like is the migration of stuff out of header files. I’m a firm believer that header files should only contain the public programming interface, along with any bookkeeping the compiler absolutely has to have And nothing else. Anything that doesn’t contribute to a person’s understanding of how to use your class shouldn’t be in there.
When I first started programming iOS I didn’t like the explicit protocols for data sources and delegates. I could understand why Apple does it, to make it explicit that “Hey! I know what I’m doing when I say I’m going to be a data source.” Things are much more explicit than what you get with an informal protocol, which is just a category. But it made the header feel kind of junky.
Say that one of my teammates on the BigLunch team wrote a view controller that lets the user choose a sandwich. It has a table view for picking the sandwich type (grinder, sub, hero, torpedo) and a spinner-picker for sandwich fillings (tofurkey, spam). The header file would look like this:
// BNRSandwichChooser.h
@interface BNRSandwichChooser : UIViewController <UITableViewDataSource,
UITableViewDelegate,
UIPickerViewDataSource,
UIPickerViewDelegate>
- (BNRSandwich *) chooseLunch;
@end // BNRSandwichChooser
The table view and picker control are just implementation details. I, as a programming using this view controller, don’t care that it uses these particular UI objects. I just want to let the user choose lunch, and then go and do other stuff with their lunch choice. But, the BNRSandwichChooser needs to adopt the protocols somewhere so that the compiler won’t complain when setting the delegate:
- (void) viewDidLoad {
self.tableView.datasource = self;
} // viewDidLoad
If the lunch chooser implementation changes to a text field or a web view, I don’t want my code to have to be recompiled because the header changed.
When Apple added class extensions, that bit of syntax that looks like a nameless category declaration, they also added the ability to to conform to protocols there:
// BNRSandwichChooser.m
#import "BNRSandwichChooser.h"
@interface BNRSandwichChooser () <UITableViewDatasource,
UIPickerViewDataSource, ...>
@end
@implementation BNRSandwichChooser
...
@end
Leaving the interface nice and minimal:
@interface BNRSandwichChooser : UIViewController
- (BNRSandwich *) chooseLunch;
@end
If you remember last time, I showed a world map that used a delegate to get information from another class, and also to inform it that stuff happened. Here is what the header looked like:
#import <Cocoa/Cocoa.h>
<b>#import "BNRWorldMapView.h"</b>
@interface BNRAppController : NSObject <NSApplicationDelegate,
<b>BNRWorldMapViewDelegate</b>>
@property (unsafe_unretained) IBOutlet NSWindow *window;
@property (weak) IBOutlet BNRWorldMapView *worldMap;
@end // BNRAppController
It is kind of junky, having to include the map header (forcing a recompile of BNRAppController if you change a comment in BNRWorldMapView.h), and adopt the protocol. To clean up the header, remove the import and the adoption, and add a @class to forward-declare the world map view so Interface Builder will know what type to target a connection to;
// BNRAppController.h
#import <Cocoa/Cocoa.h>
@class BNRWorldMapView;
@interface BNRAppController : NSObject <NSApplicationDelegate>
@property (unsafe_unretained) IBOutlet NSWindow *window;
@property (weak) IBOutlet BNRWorldMapView *worldMap;
@end // BNRAppController
And then in the implementation, I’d add the adoption to the class extension:
// BNRAppController.m
@interface BNRAppController () <b><BNRWorldMapViewDelegate></b>
@property NSMutableSet *selectedCountries;
@end // BNRAppController
The takeaway? Unless the protocol adoption has to be public for other classes to compile correctly, I now put all implementation-detail protocol adoptions into a class extension in the implementation file. This keeps the implementation details nice and hidden, and keeps the interface clean.
Our introductory guide to Swift Regex. Learn regular expressions in Swift including RegexBuilder examples and strongly-typed captures.
The Combine framework in Swift is a powerful declarative API for the asynchronous processing of values over time. It takes full advantage of Swift...
SwiftUI has changed a great many things about how developers create applications for iOS, and not just in the way we lay out our...