Sunday, May 3, 2020

Swift UI and Combine

Swift UI and Combine

Original publish date: May, 2020

SwiftUI and Combine are two new frameworks that were announced at WWDC 2019.
SwiftUI was introduced as
a revolutionary, new way to build better apps, faster.
Combine is described as
a unified declarative framework for processing values over time
These two frameworks received a lot of attention at WWDC 2019, as evidenced by the number of sessions in which these technologies were featured.

That's about 12 hours of video to watch. There are also a plethora of web sites with quick tutorials walking through how to get up and running using one or both of these frameworks. With all that information available, why am I writing a blog post on the subject?

Answer: my motivation is to simplify the existing information into something more compact and digestible. In particular, the tutorials often get down in the weeds, without tying together concepts at a higher level. In particular, much of the information focuses on either SwiftUI or Combine, but does not do a good job of describing how they work together. This blog post aims to address that short coming.

Background

SwiftUI

SwiftUI uses a declarative syntax. What does that mean? When you program declaratively, the  instructions you write say "what" to do, but not "how". A more familiar example of declarative programming is HTML, which says for example: "this is a table". It is up to the browser how to display the table. As iOS developers, we have been introduced to the paradigm of declarative programming by using constraints in auto-layout; we give general instructions of what we want done, and leave it up to the system to figure out the details.

In SwiftUI, the declarative syntax is provided by the use of a Domain Specific Language (DSL). See this talk (around 34:00). Big picture is that declaring something such as a List in SwiftUI, is done using very high level statement, which is then translated by the framework into lower level instructions.

The screenshot and code below show an app I made in 20 seconds that uses Swift UI to create a List.




Combine

Like SwiftUI, Combine is also a declarative framework. SwiftUI is a sub-type of declarative programming that uses a DSL. Combine is a different sub-type of declarative programming, namely functional programming. Wikipedia says that functional programming
is a declarative programming paradigm in which function definitions are trees of expressions that each return a value, rather than a sequence of imperative statements which change the state of the program or world.
iOS developers may have been exposed to functional programming previously if they worked on hybrid mobile applications using Redux or Redux-Flow with React Native. Or iOS developers may have used third party Swift libraries for functional programming such as RxSwift.

Apple's Combine framework provides a unified (read: single, consistent) interface for accessing and combining existing asynchronous interfaces in cocoa touch. One example of an existing asynchronous interface is URLSession, which is not replaced by but now integrates with the Combine framework.

Combine defines two interfaces: Publisher and Subscriber. A publisher sends events to subscribers. See sequence diagram below.



Putting it all Together

The above descriptions of SwiftUI and Combine may not be enough to get you up and running with these new frameworks. It may take significant study, research, learning, and practice to become familiar with either SwiftUI or Combine, separately.

But let's assume you've reached that point. Now you want to use Combine with SwiftUI. There does not seem to be an immediate connection between the two frameworks. Consider the Xcode screenshot and code below.




When previewing the app using the canvas, the image is loaded and displayed. There are just two classes to consider:

  1. ContentView -- the SwiftUI View subclass
  2. ActorViewModel -- the source of the data for the ContentView (called a ViewModel as it performs the role of VM in MVVM)

The view has a reference to the actor object, as per the class diagram below.



Although this example is using Combine, it is not immediately apparent. There is no mention of a Publisher or a Subscriber. What is going on?

Answer: Looking at the class hierarchy fills in the missing gaps. The below class diagram explains the full picture (click on the image to see it in greater detail).




Consulting Apple's documentation provides definitions for these types:

ObservedObject
A property wrapper type that subscribes to an observable object and invalidates a view whenever the observable object changes.
ObservableObject
A type of object with a publisher that emits before the object has changed. By default an ObservableObject synthesizes an objectWillChange publisher that emits the changed value before any of its @Published properties changes.
objectWillChange
A publisher that emits before the object has changed.
PassthroughSubject
A subject that broadcasts elements to downstream subscribers. As a concrete implementation of Subject, the PassthroughSubject provides a convenient way to adapt existing imperative code to the Combine model.

First, consider what the "@ObservedObject" means. This is a property wrapper. A property wrapper reduces code duplication, and allows for a succinct syntax when declaring properties that hides how the property is stored and defined. In this case, the "Observed Object" is a property which observes another object.

In other words, the property is a Subscriber (from the Combine Framework). The actor is (through the use of a property wrapper) is a Subscriber, which subscribes to a Publisher, but what is the Publisher in this scenario?

The "Observable Object" is not itself the publisher, but rather has a publisher. The ActorViewModel conforms to the "ObservableObject" protocol. By doing so, it is provided with a publisher property called "objectWillChange" by an extension (which the framework provides on the ObservableObject protocol). This "objectWillChange" property is of type "PassthroughSubject", which is a concrete type of the Publisher protocol. The passthrough subject has a property called "send", which is a publisher method used to send data to any subscribers. So the property called "objectWillChange" is the Publisher.

To recap, the Subscriber is the property called "actor" from the ContentView class, and the Publisher is the property "objectWillChange" from the ActorViewModel class. What about the need for the Subscriber to Subscribe to the Publisher? The "@ObservedObject" property wrapper is itself a Subscriber, so it must subscribe to the Publisher. But how does the View find out about changes sent to the Subscriber? That is handled by the SwiftUI framework, which we never see. There is some behind-the-scenes magic here, some details of which are eluded to by the WWDC session "Data Flow Through Swift UI".

And you might wonder, how does this work? What is this additional behavior with state? When you (use) state the framework, allocate the persistent storage for the variable on the view we have and track it as a dependency because if the system is creating storage for you, you always have to specify an initial constant value.
View can be recreated often by the system, but with state, the framework knows that it needs to persist the storage across multiple update of the same view.
....
But I want to take you behind the scene and show you what's happening when the user is tapping on the button. Let's start with view hierarchy we just showed.
We just say that when-- that when we define some state, the framework is allocating persistent storage for you. One was the special property of state variable is that SwiftUI kind of start when they change. And because SwiftUI knows that the state variable was writing the body, it knows that the view rendering depend on that state variable.
....
This is exactly what we mentioned earlier when we say that the framework manages the dependency for you. But we also talk about source of truth before and you should remember that every time you declare a state, you define a new source of truth that is owned by your view. And while this is so important that I'm showing to you in big letter, another important takeaway is that view are a function of state, not a sequence of event. Traditionally, you respond to some event by directly mutating your view hierarchy. For example, by adding or removing a subview or changing the alpha. Instead, in SwiftUI, you mutate some state and the state work as a source of truth from which you derive your view. This is where SwiftUI, declarative syntax shine. You describe your view given the current state.  

Take-away: we don't need to worry about subscribing the view to the Publisher. On the other hand, we do need to worry about making sure the publisher tell the subscriber when something is about to change. When the image has been fetched from a remote server, and the data has been transformed into an image object, we call "objectWillChange.send()" to inform the View. Once the subscriber receives notification from the publisher that something is about to / has changed, it invalidates the view (which results in the view redrawing itself).

Summary

As stated in the introduction, declarative programming is very high level and hides many of the implementation details. The way in which SwiftUI uses a ObservedObject PropertyWrapper does not on the surface give away the fact that Combine even exists in the equation. But by inspecting ObservedObject and ObservableObject, the underlying Combine framework is revealed, along with the design pattern of

subscriber --> subscribing to a publisher --> which then publishes changes --> that are received by the subscriber

There are many other ways to connect Combine and SwiftUI; this article just looked at one possible method. For example, rather than use the "objectWillChange" property, the Observed Object could instead mark its properties as "@Published", using yet another kind of property wrapper.



Thursday, April 9, 2015

Using UILayoutPriority in Swift

Swift is supposed to be a new magical language that greatly reduces the barrier to iOS and OS X development. Well, sort of...  I used to go to in-house tech talks where a computer language expert presented bits of code he had refined over the years to be more concise. This guy loved (and I mean Loved) Ruby. He went on and on about why Ruby was such a great language. But he was generally unsatisfied with all modern programming languages and often wanted to create his own. I'd love to chat with him now and see what he thought of Swift. I think he'd love it. Swift seems to incorporate most of what any mature developer wants.

The reality for many experienced Objective-C developers is that taking the existing Cocoa and Cocoa Touch libraries and making them work with Swift has been less than wonderful. Perhaps if Apple could start fresh, and re-write all the great libraries we know and love to "work with" Swift, we'd be much happier with Swift as a language. But Swift doesn't really seem to be fitting into places where Objective-C was actually working very well (for us that know Objective-C already).

Let's take a specific example: setting priority for layout constraints in code using Swift. The old way was pretty straight forward. If we wanted to set the content hugging priority for a view we would do so like this:

UIView * myView = [[UIView alloc]init];
[myView setContentHuggingPriority:UILayoutPriorityDefaultHigh 
                          forAxis:UILayoutConstraintAxisHorizontal];


Note that the use of UILayoutPriorityDefaultHigh makes it easier for us to do what we want, without having to know that the number 1000 would have the same effect, while the number 25 would not have the desired effect.

The documentation for this method looks like this:

Declaration

SWIFT
func setContentHuggingPriority(_ priority: UILayoutPriority,
                             forAxis axis: UILayoutConstraintAxis)
OBJECTIVE-C
- (void)setContentHuggingPriority:(UILayoutPriority)priority

                          forAxis:(UILayoutConstraintAxis)axis

We don't really know what a UILayoutPriority is, only that it's not an object (it's not an NSString for example). UILayoutPriority could be an integer or a float or an enum. If we look at the documentation for UILayoutPriority, this is what we find:

Declaration

SWIFT
typealias UILayoutPriority = Float
OBJECTIVE-C
enum {
  UILayoutPriorityRequired = 1000,

  UILayoutPriorityDefaultHigh = 750,

  UILayoutPriorityDefaultLow = 250,

  UILayoutPriorityFittingSizeLevel = 50,

};

typedef float UILayoutPriority;

O.K. UILayoutPriority is a float. In Objective-C, a couple of values have been pre-defined for us in an enum. We might expect that the same enums would be available to us in Swift. Certainly these two questions in Stack Overflow thought this to be a reasonble assumption: http://stackoverflow.com/questions/25881872/strange-exception-in-layoutshttp://stackoverflow.com/questions/27210527/swift-set-content-compression-resistance

But in Xcode, if you ask to see the defintion of one of these enum values (UILayoutPriorityRequired, for example), you will see that they are actually defined in the header file as constant floats.

typedef float UILayoutPriority;
static const UILayoutPriority UILayoutPriorityRequired NS_AVAILABLE_IOS(6_0) = 1000; // A required constraint.  Do not exceed this.
static const UILayoutPriority UILayoutPriorityDefaultHigh NS_AVAILABLE_IOS(6_0) = 750; // This is the priority level with which a button resists compressing its content.
static const UILayoutPriority UILayoutPriorityDefaultLow NS_AVAILABLE_IOS(6_0) = 250; // This is the priority level at which a button hugs its contents horizontally.

Very interesting. So although we may like to think of the pre-defined layout priorities as enum values (as the documentation suggests or actually blatantly states) the layout priorities are not really defined as enums; they are defined as constant floats.

The iBook says

Swift imports as a Swift enumeration any C-style enumeration marked with the NS_ENUM macro. This means that the prefixes to enumeration value names are truncated when they are imported into Swift, whether they’re defined in system frameworks or in custom code.

Excerpt From: Apple Inc. “Using Swift with Cocoa and Objective-C.” iBooks. https://itun.es/us/1u3-0.l

That means that if UILayoutPriority had been defined as an integer using the NS_ENUM macro, it would have been imported into Swift as Swift enum
For example, see this Objective-C enumeration:
OBJECTIVE-C
typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
   UITableViewCellStyleDefault,
   UITableViewCellStyleValue1,
   UITableViewCellStyleValue2,
   UITableViewCellStyleSubtitle
};

In Swift, it’s imported like this:
SWIFT
enum UITableViewCellStyle: Int {
    case Default
    case Value1
    case Value2
    case Subtitle
}

Excerpt From: Apple Inc. “Using Swift with Cocoa and Objective-C.” iBooks. https://itun.es/us/1u3-0.l

So back to what we want to do, which is to set content hugging priority. Remember that the function / method takes two parameters, the first of type UILayoutPriority and the second of type UILayoutConstraintAxis.
In Objective-C, we can either use a raw value (such as 564.75) or a pre-defined value such as UILayoutPriorityDefaultHigh. But in Swift - as of the time of this writing - there has been no porting over of the conventient pre-defined values, so you have to know and use a raw value.
What about the second value, the UILayoutConstraintAxis? The documentation states

Declaration

SWIFT

enum UILayoutConstraintAxis : Int {
    case Horizontal
    case Vertical
}
OBJECTIVE-C
enum {
   UILayoutConstraintAxisHorizontal = 0,
   UILayoutConstraintAxisVertical = 1
};
typedef NSInteger UILayoutConstraintAxis;
If you're thinking ahead, you already know what's coming next. The type of UILayoutConstraintAxis is NSInteger. It is listed in the documentation as an enum for both languages, Objective-C and Swift. So the header file in Objective-C likely defines UILayoutConstraintAxis using the NS_ENUM macro. Let's see if that's true.

//
// UIView Constraint-based Layout Support
//

typedef NS_ENUM(NSInteger, UILayoutConstraintAxis) {
    UILayoutConstraintAxisHorizontal = 0,
    UILayoutConstraintAxisVertical = 1
};

Yes, indeed, as expeted UILayoutConstraintAxis is defined as an NSInteger using the NS_ENUM macro. So that's why we can use the enum value UILayoutConstraintAxisHorizontal in either language. The two enum values have been imported from Objective-C to Swift.
So we have discussed two ways to know if a pre-defined value you are used to using in Objective-C is available in Swift:
  1. check the documentation
  2. check the header file in Objective-C (found by right-clicking the value and then selecting "Jump to Definition")
There is one more way to see if a typedef you are used to using is a constant or an enum. In code, test to see if the address of the constant exists. Constants have a memory address, while enums do not. See the code below.

// this line will compile and run just fine. 
// UILayoutPriorityDefaultHigh is a constant and has a memory address
// the value will be true if the device is running iOS 6.0 or later
// and false otherwise
BOOL predefinedValueIsAvailable = (NULL != &UILayoutPriorityDefaultHigh);

// this line will not compile
// UILayoutConstraintAxisHorizontal is an enum (NOT a constant) 
// and does not have a memory address
predefinedValueIsAvailable = (NULL != &UILayoutConstraintAxisHorizontal);

So Swift may not be the Pancea we expect if we have a lot of Objective-C knowledge and habits. Perhaps eventually we will displace this knowledge with the Swift way of doing thigs. In the meantime, remember not to assume that every single nuance of what you're used to doing in Objective-C is immediately available and identical in Swift. Check the documentation; it often helps!

Tuesday, April 7, 2015

Accessing Shared Data Between iOS Applications

An application sandbox - in the Apple Software development world - is a safe place for your application. The metaphor is to a playground with several sandboxes. Each sandbox is self-contained and does not interact with each other. The sand, toddlers, and toys in one sandbox are kept isolated from the others. So it is with the Operating System (the playground), the applications which run on top of the operating system (the sandbox), and the protection to user data and other resources (sand, toddlers, and toys) provided by each sandbox.

On the desktop (OS X), developers can choose to opt in to App Sandboxes or not. More than just protecting files, applications can be cut off from accessing the network, the user's camera, and other resources. This may not sound like a good idea to the individual developer, but the end result is providing greater security to the user. If every app worked within an app sandbox, it would greatly limit the amount of damage any one malicous app could inflict upon other applications and the user's system in general.

App Sandboxing is such a good idea that Apple decided to make it the only way to create iOS applications. Although the implementation behind sandboxing applications in iOS is slighly different than OS X, the intent and the result is basically the same. Every iOS application is contained on the user's hard drive in an application bundle. The application bundle contains the code which the application needs to run, as well as static resources (images, video files, etc. that do not change) as well as data files which the application may create, or modify at runtime.

Only allowing one application to access files whithin its own sandbox has obvious drawbacks: no files can be shared between applications. Recently Apple has eased this limitation somewhat; applications which are created by the same developer (or the same team) can share resources. This exception is provided by a mechanism known as entitlements.

Entitlements are what Apple uses to define privledges an application has or does not have. There are entitlements for being able to install a test version of an application, entitlements for allowing an application to access Apple Push Notification Services, entitlements for allowing apps to access in-store purchases, entitlements for enabling iCloud, and many others. Of interest to us is the entitlement which allows applications to share data. This entitlement is what Apple calls the "com.apple.security.application-groups" entitlement.

The concept behind more than one application being part of a group which trusts each other is called an "App Group". The app group must have an identifier (a uniquely identifying string). When you create an app group, Xcode does the following with the com.apple.security.application-groups entitlement:
  • adds the App Group entitlement to your entitlements file
  • adds the App Group entitlement to your App ID
  • adds the App Group Containers entitlement to your App ID
When you create an App Group, any app which you add to that app group has access to a shared container and is also able to communicate with one another. The shared container is the place where you will read and write files that are meant to be shared within the group.

The Mac (OS X) App Sandbox Design Guide states

The container is in a hidden location, and so users do not interact with it directly. Specifically, the container is not for user documents. It is for files that your app uses, along with databases, caches, and other app-specific data.


In the iOS world, the user is not exposed directly to the file system, but instead applications manage files on behalf of the user. Even developers do no specify absolute file locations. Developers just ask the Operating System for the location of a folder, such as the documents directory. In the case of a shared directory between apps in an app group, the location of the shared container may be found by calling this method:

- (NSURL *)containerURLForSecurityApplicationGroupIdentifier:(NSString *)groupIdentifier

Provided that we have correctly provisioned our application with the correct App ID, App group ID, and entitlements, calling this one line of code is all we need to do to access files which are shared inside the app group.

References 

Configuring App Groups
NSFileManager Class Reference
Entitlement Key Reference
App Sandbox Design Guide



Sunday, April 5, 2015

Passing Data Between View Controllers

Recently I found this question on StackOverflow:

I'm new to iOS and Objective-C and the whole MVC paradigm and I'm stuck with the following:

I have a view that acts as a data entry form and I want to give the user the option to select multiple products. The products are listed on another view with a tableview controller and I have enabled multiple selections.

Question:

My question is, how do I transfer the data from one view to another? I will be holding the selections on the tableview in an array, but how do I then pass that back to the previous data entry form view so it can be saved along with the other data to core data on submission of the form?

I have surfed around and seen some people declare an array in the AppDelegate. I read something about Singletons but don't understand what these are and I read something about creating a data model.

What would be the correct way of performing this and how would I go about it?


There were some pretty good answers that addressed part of the question, but not all of it. The top voted answer gave a top notch explanation of how to pass information between two view controllers. But it did not make any mention of AppDelegate or Singleton. It also said next-to-nothing about a data model. None of the top answers considered what would be an appropriate solution if more than two view controllers needed to communicate to each other. This blog post fills in all these missing pieces.

I'm going to give a full answer. This post will discuss:
  • sharing data between two view controllers
  • sharing data between more than two view controllers
  • delegates
  • observer pattern
  • singletons
  • appDelegate

Application Scenarios

Rather than having a highly hypothetical, abstract discussion, it helps to have concrete applications in mind. To help define a two-view-controller situation and a more-than-two-view-controller situation, I am going to define two concrete application scenarios.

Scenario one: maximum two view controllers ever need to share information.
See diagram below.


There are two view controllers in the application. There is a ViewControllerA (Data Entry Form), and View Controller B (Product List). The items selected in the product list must match the items displayed in the text box in the data entry form. In this scenario, ViewControllerA and ViewControllerB must communicate directly with each other and no other view controllers. When the user is in the data entry form, and wishes to change the selected products, the application performs a transistion (in the case of storyboards, a segue is performed) from the data entry form to the product list. The product list must know which products were previously listed on the data entry form, to correctly show these items as already selected. Therefore as part of the transition / segue, there needs to be data passed from ViewControllerA to ViewControllerB.

Likewise, there is a reverse relationship. When the user finishes selecting products on the product list, the product list view controller is dismissed, and a transition occurs (or a segue) from the product list view controller back to the data entry form view controller. Before the data entry form can display itself properly, it needs to know about changes to the selected products. Therefore as part of the transition from ViewControllerB back to ViewControllerA, there needs to be data passed from ViewControllerB to ViewControllerA.

Scenario two: more than two view controllers need to share the same information.
See diagram two.

There are four view controllers in the application. It is a tab-based application for managing home inventory. Three view controllers present differently filtered views of the same data:
  • ViewControllerA - Luxury Items
  • ViewControllerB - Non-insured Items
  • ViewControllerC - Entire Home Inventory
  • ViewControllerD - Add New Item Form
Any time an individual item is created or edited, it must also synchronize with the other view controllers. For example, if we add a boat in ViewControllerD, but it is not yet insured, then the boat must appear when the user goes to ViewControllerA (Luxury Items), and also ViewControllerC (Entire Home Inventory), but not when the user goes to ViewControllerB (Non-insured Items). We need be concerned with not only adding new items, but also deleting items (which may be allowed from any of the four view controllers), or editing existing items (which may be allowed from the "Add New Item Form", repurosing the same for for editing).

Since all the view controllers do need to share the same data, all four view controllers need to remain in synchronization, and therefore there needs to be some sort of communication to all other view controllers, whenever any single view controller changes the underlying data. It should be fairly obvious that we do not want each view controller communicating directly with each other view controller in this scenario. In case it is not obvious, consider if we had 20 different view controllers (rather than just 4). How difficult and error prone would it be to notify each of the other 19 view controllers any time one view controller made a change?

The Solutions: Delegates and the Observer Pattern, and Singletons

In scenario one, we have two viable solutions:
  • Segues
  • Delegates
The Segue solution involves performing view controller transitions using Storyboards and segues. A property can be set on the destination view controller when the segue is triggered (see Apple's Developer Documentation: https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ManagingDataFlowBetweenViewControllers/ManagingDataFlowBetweenViewControllers.html).

The Delegate solution involves making one view controller the delegate of another. Typically the view controller on the top of the navigation stack, the one which was just presented, would NOT be the delegate, but rather would call delegate methods on the view controller which presented it.

In the scenario one, the Product List would have a delegate property, and the Data Entry Form would be the delegate. Being the delegate means conforming to a protocol by implementing the delegate methods, and then setting itself as the delegate before presenting the Data Entry Form.

In scenario two, we have other viable solutions:
  • Observer Pattern
  • Singletons
A singleton is an instance of a class, that instance being the only instance in existence during its lifetime. A singleton gets its name from the fact that it is the single instance. Normally developers who use singletons have special class methods for accessing them. An extra level of security to ensure that no one accidentally creates more than one instance at one time is to also override the init method. See the code below.

- (id) init {
    static BOOL alreadyInitialized = NO;
    if (alreadyInitialized) {
        // we want to prevent callers from "accidentally"
        // initializing more than one instance of this class
        return self;
    }
    alreadyInitialized = YES;
    
    self = [super init];
    if (self) {
        [self managedObjectContext];
    }
    return self;
}

+ (HouseholdInventoryManager*) sharedManager; {
    static dispatch_once_t onceQueue;
    static HouseholdInventoryManager* _sharedInstance;
    
    // dispatch_once is guaranteed to only be executed once in the
    // lifetime of the application
    dispatch_once(&onceQueue, ^{
        _sharedInstance = [[self alloc] init];
    });
    return _sharedInstance;
}

Now that we understand what a singleton is, let's discuss how a singleton fits into the observer pattern. The observer pattern is used for one object to respond to changes by another object. In the second scenario, we have four different view controllers, who all want to know about changes to the underlying data. The "underlying data" should belong to a single instance, a singleton. The "know about changes" is accomplished by observing changes made to the singleton.

Putting these pieces together, for scenario two we would have various model classes representing the household inventory items. For example, a household inventory item may look like the following class definition.

@interface JGCHouseholdInventoryItem : NSObject
@property (nonatomic, copy) NSString * itemName;
@property (nonatomic, strong) NSNumber * originalPrice;
@property (nonatomic, copy) NSDate * purchaseDate;
@property (nonatomic, strong) UIImage * photo;
@property (nonatomic, copy) NSString * itemDescription;
@property (nonatomic, assign, getter=isLuxuryItem) BOOL luxuryItem;
@property (nonatomic, assign, getter=isInsured) BOOL insured;
@end

The home inventory application would have a single instance of a class which is designed to manage a list of inventory items. In the iOS world, a singleton that performs a management functionality is often called a "manager". So the class method for getting the single data manager instance is called "sharedManager". The manager would manage a collection of household items. The following is a class definition for the data manager:

#import <Foundation/Foundation.h>

@class JGCHouseholdInventoryItem;

@interface HouseholdInventoryManager : NSObject
/*!
 The global singleton for accessing application data
 */
+ (HouseholdInventoryManager*) sharedManager;

- (NSArray *) entireHouseholdInventory;
- (NSArray *) luxuryItems;
- (NSArray *) nonInsuredItems;

- (void) addHouseholdItemToHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) editHouseholdItemInHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) deleteHoueholdItemFromHomeInventory:(JGCHouseholdInventoryItem*)item;
@end

When the collection of home inventory items changes, the view controllers need to be made aware of this change. The class defintion above does not make it obvious how this will happen. We need to follow the observer pattern. The view controllers must formally observe the sharedManager. There are two ways to observe another object:
  • Key-Value-Observing (KVO)
  • NSNotificationCenter
In scenario two, we do not have a single property of the HouseholdInventoryManager which could be observed using KVO. We have purposefully kept the array of household items internal. In fact, we could internally be using a dictionary or a set to store the household items, and just providing arrays when the getter methods are called. Because we do not have a single property which is easily observable, the observer pattern in this case must be implemented using NSNotificationCenter. Each of the four view controllers would subscribe to notifications, and the sharedManager would send notifications to the notification center when appropriate. The inventory manager does not need to know anything about the view controllers or instances of any other classes which may be interested in knowing when the collection of inventory items changes; the NSNotificationCenter takes care of these implementation details. The View Controllers simply subscribe to notifications, and the data manager simply posts notifications.

For more information on Observers and Delegates see this post: http://jasoncross-ios-development.blogspot.com/2015/04/asynchronous-json-requests-in-objective.html.

Application Delegate and Singletons

The original poster of the question on StackOverflow had seen some people declare an array in the AppDelegate. This equates to taking a collection of model objects (the array) and placing it in a singleton (the AppDelegate). This is similar to the solution proposed above, but certainly not identical.

Many beginner programmers take advantage of the fact that there is always exactly one Application Delegate in the lifetime of the application, which is globally accessible. Beginning programmers use this fact to stuff objects and functionality into the appDelegate as a convenience for access from anywhere else in the application. Just because the AppDelegate is a singleton doesn't mean it should replace all other singletons. This is a poor practice as it places too much burden on one class, breaking good object oriented practices. Each class should have a clear role that is easily explained, often just by the name of the class.

Any time your Application Delegate starts to get bloated, start to remove functionality into singletons. For example, the Core Data Stack should not be left in the AppDelegate, but should instead be put in its own class, a coreDataManager class. The final solution proposed in this blog post has a clear separation of duties between classes, minimizing interactions and dependencies.
AppDelegate
kept lean and mean to perform only core duties related to the application and the OS
ViewControllers
control the views they contain, passing along model information as needed. Do not need to know about every other view controller.
Model
used to represent the data which the ViewControllers ask the views to present. Bare bones classes that store data.
Data Manager
HouseholdInventoryManager. A singleton which manages the data for the entire application. Knows about the model objects, and transforms the data as needed (filtering when asked). Knows nothing about the ViewControllers.
Notification Center
manages an internal list of notifications: keeps track of observers. When notifications are posted, passes these along to the subscribed observers. Knows about the ViewControllers because they have added themselves as observers. Does not necessarily know anything about the HouseholdInventoryManager (just processes post request from any object).
Now the original question has been fully answered: the reader should now know about passing information between view controllers in two different scenarios (only two or more than two view controllers needing to communicate), what is a singleton and how to create one and when to use one, and finally the appropriate use of the AppDelegate.

Thursday, April 2, 2015

Asynchronous JSON requests in Objective-C

One of the most common patterns in iOS development is the display of data which originates from a Web Service and is transmitted via JSON. This post discusses synchronous and asynchronous fetching of data, and other related design patterns.

What is the difference between synchronous and asynchronous http requests? In a synchronous http request, the currently executing code "blocks" (stops and waits) until the request finishes. If this code is on the main thread, then the app will appear frozen and broken while the network call is made. This is a bad idea, is against best practices, and should always be avoided.

In contrast, an asynchronous http request allows the currently executing code to continue while the request is initiated and while the request is running. Once the request completes, the code "reports back" to a listener. In the case of  NSURLConnection sendAsynchronousRequest:queue:completionHandler: , the listener is the caller of the method who passes in a block as a method argument. In the case of network requests being made from the main thread, the User Interface does not lock, the application continues to respond to user gestures, and is the accepted best practice.

In a nutshell, that's all you need to know: use the asynchronous method. But that begs the question: why is the synchronous method even available if it should never be used? The answer is that there are many scenarios when making a synchronous request makes sense. Detailing some of these scenarios comprises the remainder of this post.

Model-View-Controller (MVC)

It is no secret that MVC is the most prevalent design pattern seen in iOS development. The View Controller does a lot of heavy lifting. But that doesn't mean that it should do all the work. Views are generally responsible for how they render themselves; view controllers may give views general directions such as change position or change state. A common mistake in beginning iOS developers is to put all the model code inside the View Controller. Experienced developers see the benefits of having separate model classes, and sometimes even separate classes that manage these models.

Since many iOS applications fetch data from a Web Service in JSON format, it makes sense to have Model classes that mirror the JSON objects. But what about the fetching of the JSON data, where should this code go: in the View Controller or in the Model? An argument could be made for either, however a better solution is to put the data fetching in yet another class. Following good Object Oriented Programming (OOP) means that each class has a single duty that is easily explained.

Service Layer

I learned a really valuable lesson from a co-worker while doing full-stack ASP.Net C# development. We had a 3-tiered architecture: a Database layer, a Web Server layer, and a web browser layer. The Web Server fetched data from the Database and then served this data to the web browser in JSON. However, the web service did not just embed raw SQL scripts in the same classes which were serving the JSON. This would not have followed the clean separation of duties referred to above, and would have resulted in duplicate code that was very hard to debug and maintain. Instead, we had several classes in the web server that looked after getting data from the database:

  • model classes. These often mirrored the entities in the Database
  • service layer. These classes called SQL stored procedures to get database objects, and converted the database objects to the model classes (C# objects)
  • web server API classes. These classes handled API requests for JSON data, and called upon the service layer for data as needed to respond to the the API requests with data.
One of the benefits to this approach was that if we changed the database server location, language, or stored procedures, the change was needed only in the service layer. The model classes and the web server API classes were un-affected.

I took the lessons learned from building full-stack web applications, and applied them to building iOS applications. Now the service layer fits as follows:
  • model classes. These often mirror the JSON objects
  • service layer. These classes know about the API and make network calls to fetch JSON. When the network calls complete, JSON is converted to native model classes (Objective-C objects).
  • View controller. These classes handle user interaction and ask for data from the service layer as needed.
The astute reader may have just had an "ah-ha" moment when they read about making network calls and doing something when complete. Because the service layer is not a view controller, it need not be running on the main thread, and therefore could make use of synchronous http requests.

Now that we have a good understanding of how to architect an iOS application to fetch and convert JSON data, all that is left is to discuss the interaction between the View Controller and the application data.

Blocks

It is sometimes the case that an iOS application is not very concerned with the staleness of data; the iOS application only fetches data once when it first starts and does not make any subsequent API calls to find out if there is newer data available. In this case, the application only has two states:

  1. no data (after first starting and before network call completion)
  2. there is data (after a successful network call)

We're not always lucky to have such a simple scenario, but if so, an appropriate solution is to use blocks. A block is a piece of code that we can pass as a method parameter, that may get called at some point in the future. A method which belongs to a service class, and which takes a block as a parameter, may look something like this:

typedef void (^JGCResponseBlock) (NSArray* arrayOfObjects, NSError * error);

- (void) fetchDataFromAPIWithResponseBlock:(JGCResponseBlock)responseBlock;

The caller (a View Controller), can call ask the service class to fetch some data for the View Controller. When the data has been fetched (or the fetch fails), the service class uses the block to inform the View Controller. The View Controller may implement the block as follows:

[serviceLayer fetchDataFromAPIWithResponseBlock:^(NSArray * arrayOfObjects, NSError *error) {
        
        if (nil != error) {
            // deal with error appropriately
        }
        else if (nil != arrayOfObjects) {
            // update the user interface
        }

    }];

One of the benefits to using blocks is that the code which deals with the API results is declared inline with the method call which asks for data from the API. But remember that blocks are only the best solution for gluing together the model and the View Controller when the data is not expected to change. If the model objects change, we need another solution.

Delegates and Observers

It is a very common scenario in iOS development that views need to know when the model objects whose information the views are presenting changes. When one object changes state, other objects may be notified either by using a delegate or by using an observer pattern.

Delegates

Delegates are classes which implement a protocol, a protocol which defines methods that an object may use to inform the delegate that a change in state is about to occur or has occurred. Delegate methods which report a change in state should contain with the verbs “will” or “did”, such as

tableView:willDisplayCell:forRowAtIndexPath
tableView:didEndDisplayingCell:forRowAtIndexPath

The class which “calls back” the delegate, must first check to see that the delegate responds to selector before calling the callback method. This may not be necessary if the protocol method is required, but must be done when the protocol method is optional.

Classes which have a delegate should declare the delegate as a weak property. The rationale for specifying the delate’s property attribute as weak is a follows: It is normal that the delegate already has a strong reference to the class for which it is a delegate (for example, a view controller with a reference to a table view, sets itself as a delegate to the table view). If two classes have strong references to each other, neither is ever released, resulting in a memory leak.

Observers

There are two ways to implement observers in iOS:
  1. NSNotificationCenter
  2. Key-Value-Observing

Best practices for using NSNotificationCenter include using constant strings to identify the NSNotification, using the same constant in the notifier and the receiver. Receivers must unsubscribe from the NSNotificationCenter in dealloc or when they are no longer interested in receiving notifications.

In order to use Key-Value-Observing, any programmatic changes to the observed property must occur using one of three mechanisms:
  1. call the synthesized setter, for example:
    self.total = 20;
  2. change the property using Key-Value-Coding, for example:
    [self setValue:20 forKey:@”total”];
    
  3. trigger notification of the observers, for example:
    [self willChangeValueForKey:@”total”];
    total = 20;
    [self didChangeValueForKey:@”total”];
    
The following table should be used as a guide when determining how one object notifies others of its change in state.



Criteria
Delegate
NSNotificationCenter
Key-Value-Observing
a change in one object requires a change in only one other object
YES
NO
OK (1 or more)
a change in one object requires a change in more than one other object
NO
YES
OK (1 or more)
the change in state is something which may be represented by a single property of one specific object
OK (1 or more)
NO
YES
the change in state is something which may not be represented by a single property of one specific object
OK (1 or more)
YES
NO

Let's look at some examples.

You have a model object called Post, which has three four properties: postDate, postText, postImage, and postFavoriteCount. After the object is created from the server JSON, the only property expected to change is the postFavoriteCount. So it would be perfectly acceptable to use Key-Value-Observing (KVO) on the postFavoriteCount property. As many other objects as needed could observe this property, and would be notified when it changed. However, suppose we added a new property called rePostCount, which was also expected to change. Now View Controllers would need to subscribe to two properties via KVO: postFavoriteCount, and rePostCount. As more and more state changes need to be communicated, a better solution would be delegates or NSNotificationCenter.

One more example: you have a table view that needs to update when the underlying data changes. If there is only one object (the View Controller which contains the table view) in the entire application which needs to know when the data changes, then using the delegate pattern to inform the view controller that the table view's data has changed work quite well. However, if more than one view controller needs to know about an underlying data change, then NSNotificationCenter is the only option out of the two.

It is not too hard to read documentation and learn the syntax of Objective-C. Swift is even easier. However, it's also easy to make a lot of mistakes in architectural decisions (or lack of decisions) when first starting as an iOS developer. It's only normal, natural, and expected to make mistakes. After all, that's how we learn. But learning from other's mistakes can often save you time, because you aren't left cleaning up the mess that you would have created, had you made the same mistake. This article should give the novice programmer some rules to follow when figuring out how to turn JSON from a web service into a functioning iOS application.

Wednesday, April 1, 2015

Checking for Device Features - the Right Way

As an iOS Developer, you want as many people as possible to be able to use your application. You may support a variety of Operating System versions, hardware models and hardware versions. This article will make your job a little bit easier.

Consider the different screen sizes and resolutions of iPhone 5, iPhone 6, iPhone 6 Plus, iPad, iPad Retina, iPad Mini. Using auto-layout is often all you need to re-use a single storyboard that will create User Interface layouts that work for all screens. But what if your app needs to know more than just screen resolution, say, if there is a camera or not, and at what resolution?

In the past, it was easy to assume that certain hardware versions had specific features. But as more devices were released, tying code to specific hardware versions became increasingly difficult. The recommended (by Apple) best practice has always been to test for specific functionality, not for specific hardware versions. Let's see some examples.

The below table has three columns. The first is the question the developer wants answered. The second column is the wrong way to answer the question; the last column is a better way.


Desired Information
Wrong
Right
does this device have a front camera?
NSString* valueDevice = [[UIDevice currentDevice] model];
if(value==@"iPhone3,1

" ) {
// the iPhone 4 was the first device to 
// have a front facing camera
// future devices, bad luck
}

NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
AVCaptureDevice *captureDevice = nil;
for (AVCaptureDevice *device in videoDevices)
{
   if (device.position == AVCaptureDevicePositionFront)
   {
       captureDevice = device;
       break;
   }
}
does this device have a high resolution screen
NSString* valueDevice = [[UIDevice currentDevice] model];
if(value==@"iPhone4,1
" ) {
// the iPhone4S was first to have a 
// high res screen
// future devices, bad luck
}
BOOL hasHighResScreen = NO;
if ([UIScreen instancesRespondToSelector:@selector(scale)]) { 
// only if supporting iOS < 4.0
   CGFloat scale = [[UIScreen mainScreen] scale];
   if (scale > 1.0) {
       hasHighResScreen = YES;
   }
}
can this device use Passbook?
if ([[[UIDevice currentDevice] systemVersion] floatValue] > 6.0) {
   // any OS newer than iOS6 is
// *assumed* to have PassLibrary
}
- (BOOL) canUsePassLibrary {
   Class libraryClass = NSClassFromString(@"PKPassLibrary");
   if(libraryClass && [libraryClass  performSelector:@selector(isPassLibraryAvailable)]) {
       // the method isPassLibraryAvailable 
// returns a BOOL
       return YES;
   }
   return NO;
}
can I use a Core Location Activity Type
#if __IPHONE_6_0
CLLocationManager * manager = [[CLLocationManager alloc] init];
CLActivityType type = [manager activityType];

#endif
CLLocationManager * manager = [[CLLocationManager alloc] init];
   if ([manager respondsToSelector:@selector(activityType)]) {
       id typeOfActivity = [manager performSelector:@selector(activityType)];
       // CLActivityType is an enum that is 
// only defined in iOS 6 or higher
       // and we can't directly test if an enum 
// is defined
   }

When checking for certain features, Apple often has methods which will tell you whether or not that feature is available. Try looking for these methods before creating your own.
However, there is a caveat to using this method: if you try and use a method on a device which is running an older Operation System which does not recognize that method (because the framework is not available), a fatal error will result. This is not easy to check using the iOS simulator. Here is how you check for the existence of the required part of a framework before jumping and using it:



Desired code to use
How to test first
Class
Class someClass = NSClassFromString(@”PKPassLibrary”);
if(someClass) { //.....}
Method
if ([thisObject respondsToSelector:@selector(someMethod)]) { //..... }
Constant
BOOL isKeyboardBoundsKeyAvailable = (&UIKeyboardBoundsUserInfoKey != NULL);
if (isKeyboardBoundsKeyAvailable) {
 // UIKeyboardBoundsUserInfoKey defined
}
enum
unfortunately, there is no direct way to test if an enum exists, so instead find a method which should be available when the enum is available
e.g. the enum CLActivityType is a typedef for an enum, defined in iOS 6. Fortunately, the class also has a property which uses this type, called activityType, and properties can be tested as getters/setters

As the above table shows, if you want to know if a Class is available, try creating a class from a string. On devices where the Class is unavailable, the "if (someclass)" condition will fail, and the code inside the block will not be executed.

Likewise, if you want to know if a certain method is available, test using "respondsToSelector". Sometimes newer OS versions have constants which are not defined in earlier versions. The solution in this case is to test if the address of the constant is "NULL".  However, dealing with enumerations is trickier. As the table states, we cannot test directly for the definition of an enum, so instead our best guess it to look for something else (a property, method, or constant) which was released as part of the same group of technology as the enum.

As a professional iOS developer, you may be glad that applications require constant maintenance. But you want to protect your reputation that would be tarnished if your apps crashed or lost functionality when newer devices were released. No code is truly "future-proof" forever. However, by following the advice in this article, your code will be more reliable and require less maintenance.