Communication Between Objects - Cocoa - iOS 7 Programming Fundamentals: Objective-C, Xcode, and Cocoa Basics (2014)

iOS 7 Programming Fundamentals: Objective-C, Xcode, and Cocoa Basics (2014)

Part III. Cocoa

Chapter 13. Communication Between Objects

As soon as an app grows to more than a few objects, puzzling questions can arise about how to send a message or communicate data between one object and another. The problem is essentially one of architecture. It may require some planning to construct your code so that all the pieces fit together and information can be shared as needed at the right moment. This chapter presents some organizational considerations that will help you arrange for one object to be able to communicate with another.

The problem of communication often comes down to one object being able to see another: the object Manny needs to be able to find the object Jack repeatedly and reliably over the long term so as to be able to send Jack messages.

One obvious solution is an instance variable of Manny whose value is Jack. This is appropriate particularly when Manny and Jack share certain responsibilities or supplement one another’s functionality. The application object and its delegate, a table view and its data source, a view controller and the view that it controls — these are cases where the former must have an instance variable pointing at the latter.

This does not necessarily imply that Manny needs to assert ownership of Jack (as a matter of memory management policy, Chapter 12). An object does not typically retain its delegate or its data source; similarly, an object that implements the target–action pattern, such as a UIControl, does not retain its target. But then Manny must be prepared for the possibility that its supposed reference to Jack will turn out to be a reference to nil; and care must be taken that this reference doesn’t turn into a dangling pointer (luckily, that’s less likely to happen under ARC). On the other hand, a view controller is useless without a view to control; once it has a view, it will retain it, releasing it only when it itself goes out of existence. There may be similar situations in which you do want one object to own another.

Objects can also perform two-way communication without holding persistent (instance variable) references to one another. For example, Manny might send a message to Jack where one of the parameters is a reference to Manny; this might merely constitute a form of identification, or an invitation to Jack to send a message back to Manny if Jack needs further information while doing whatever this method does. Again, this is a common pattern. The parameter of the delegate message textFieldShouldBeginEditing: is a reference to the UITextField that sent the message. The first parameter of a target–action message is a reference to the sender. Manny thus makes itself, as it were, momentarily visible to Jack; Jack should not wantonly retain Manny (especially since there’s an obvious risk of a retain cycle).

But how is Manny to obtain a reference to Jack in the first place? That’s a very big question. Much of the art of iOS programming, and of object-oriented programming generally, lies in one object getting a reference to some other object. (See also my discussion of this matter in Chapter 5.) Every case is different and must be solved separately, but certain general patterns emerge, and this chapter will outline them.

There are also ways for Manny to send a message that Jack receives without having to send it directly to Jack, or without knowing or caring who Jack is. Notifications and key–value observing are examples, and I’ll discuss them in this chapter as well.

Finally, the chapter ends with a section on the larger question of what kinds of objects need to see one another, within the general scope of a typical iOS program.

Visibility by Instantiation

Every instance comes from somewhere and at someone’s behest: some object sent a message commanding this instance to come into existence in the first place. The commanding object therefore has a reference to the instance at that moment. When Manny generates Jack, Manny has a reference to Jack.

That simple fact can serve as the starting point for establishment of future communication. If Manny generates Jack and knows that it (Manny) will need a reference to Jack in the future, Manny can keep the reference that it obtained by generating Jack in the first place. Or, it may be that what Manny knows is that Jack will need a reference to Manny in the future; Manny can supply that reference immediately after generating Jack, and Jack will then keep it.

Delegation is a case in point. Manny may create Jack and immediately make itself Jack’s delegate. Indeed, if this crucial, you might endow Jack with an initializer so that Manny can create Jack and hand Jack a reference to itself at the same time, to help prevent any slip-ups. Compare the approach taken by UIActionSheet and UIAlertView, where the delegate is one of the initializer’s parameters, or by UIBarButtonItem, where the target is one of the initializer’s parameters.

But delegation is just one example. When Manny creates Jack, it might not be a reference to Manny that Jack needs, but to something that Manny knows or has. You will presumably endow Jack with a method so that Manny can hand that information across; again, it might be reasonable to make that method Jack’s initializer, if Jack simply cannot live without the information.

This example, from one of my apps, is from a table view controller. The user has tapped a row of the table. We create a secondary table view controller, a TrackViewController instance, handing it the data it will need, and display the secondary table view. I have deliberately devised TrackViewController to have a designated initializer initWithMediaItemCollection: to make it virtually obligatory for a TrackViewController to have access, from the moment it comes into existence, to the data it needs:

- (void)showItemsForRow: (NSIndexPath*) indexPath {

// create subtable of tracks and go there

TrackViewController *t =

[[TrackViewController alloc] initWithMediaItemCollection:


[self.navigationController pushViewController:t animated:YES];


In that example, self does not keep a reference to the new TrackViewController instance, nor does the TrackViewController acquire a reference to self. But self does create the TrackViewController instance, and so, for one brief shining moment, it has a reference to it. Therefore selftakes advantage of that moment to hand the TrackViewController instance the information it needs. There will be no better moment to do this. Knowing the moment, and taking care not to miss it, is part of the art of data communication.

When a nib loads, the nib’s owner is effectively instantiating the objects in the nib. (For a .xib file, the owner is the object represented by the File’s Owner proxy in the nib; for a storyboard, it is a scene’s top-level view controller. See Chapter 7.) By preparing outlets from the nib’s owner in the nib, you arrange that the nib’s owner will obtain references to the instantiated nib objects at the moment they are instantiated through the nib-loading mechanism.

A slightly different architecture arises when Manny does not instantiate Jack; Moe does. But Moe has a reference to Manny, and Moe knows that Manny might have information to share with Jack. Therefore Moe brings Manny and Jack together. That is Manny’s moment.

For example, beginners are often puzzled by how two objects are to get a reference to one another if they will be instantiated from different nibs — either different .xib files or different scenes in a storyboard. It is frustrating that you can’t draw a connection between an object in nib A and an object in nib B; it’s particularly frustrating when you can see both objects sitting right there in the same storyboard. But as I explained earlier (Connections Between Nibs), such a connection would be meaningless, which is why it’s impossible. These are different nibs, and they will load at different times. However, some object (Manny) is going to be the owner when nib A loads, and some object (Jack) is going to be the owner when nib B loads. Perhaps they can then see each other, in which case, given all the necessary outlets, the problem is solved. Or perhaps some third object (Moe) can see both of them and provides a communication path for them.

In a storyboard, that’s exactly what does happen. When a segue in a storyboard is triggered, the segue’s destination view controller is instantiated, and the segue has a reference to it. At the same time, the segue’s source view controller already exists, and the segue has a reference to it as well. So the segue sends the source view controller the prepareForSegue:sender: message, containing a reference to itself (the segue). The segue is Moe; it is bringing Manny (the source view controller) and Jack (the destination view controller) together. This is the source view controller’s chance (Manny’s moment) to obtain a reference to the newly instantiated destination view controller (by asking the segue for it) — and now the source view controller can make itself the destination view controller’s delegate, hand it any needed information, and so forth. (If you make a project from the Utility Application template, you can see this very thing happening in the MainViewController code.)

Visibility by Relationship

Objects may acquire the ability to see one another automatically by virtue of their position in a containing structure. Before worrying about how to supply one object with a reference to another, consider whether there may already be a chain of references leading from one to the other.

For example, a subview can see its superview, through its superview property. A superview can see all its subviews, through its subviews property, and can pick out a specific subview through that subview’s tag property, by calling viewWithTag:. A subview in a window can see its window, through its window property. Thus, by working up or down the view hierarchy by means of these properties, it may be possible to obtain the desired reference.

In this example from my own code, I have many buttons and many text fields, paired with one another. When a button is tapped, I need to fetch the text of the corresponding text field. Given a particular button, how can I get a reference to the corresponding text field? To make this possible, I’ve assigned the buttons tags in the nib (101, 102, 103, and so on) and I’ve given the text fields corresponding tags (1, 2, 3, and so on):

UIView* v = sender; // a button

UIView* v2 = [v.superview viewWithTag:(v.tag - 100)];

Similarly, a responder (Chapter 11) can see the next responder in the responder chain, through the nextResponder method — which also means, because of the structure of the responder chain, that a view controller’s main view can see the view controller. In this code, I work my way up from a view to obtain a reference to the view controller that’s in charge of this whole scene:

UIResponder* r = self; // a UIView in the interface

while (![r isKindOfClass:[UIViewController class]])

r = r.nextResponder;

Similarly, view controllers are themselves part of a containment hierarchy and therefore can see one another. If a view controller is currently presenting a view through a second view controller, the latter is the former’s presentedViewController, and the former is the latter’spresentingViewController. If a view controller is contained by a UINavigationController, the latter is its navigationController. A UINavigationController’s visible view is controlled by its visibleViewController. And from any of these, you can reach the view controller’s view through its view property, and so forth.

All of these relationships are public. So if you can get a reference to just one object within any of these structures or a similar structure, you can effectively navigate the whole structure through a chain of references and lay your hands on any other object within the structure.

Global Visibility

Some objects are globally visible — that is, they are visible to all other objects. Class objects are a trivial example! But classes often have class methods that vend singleton instances. Some of these singletons, in turn, have properties pointing to other objects, making those other objects likewise globally visible.

For example, any object can see the singleton UIApplication instance by calling [UIApplication sharedApplication]. So any object can also see the app’s primary window, because that is the singleton UIApplication instance’s keyWindow property, and any object can see the app delegate, because that is its delegate property. And the chain continues: any object can see the app’s root view controller, because that is the primary window’s rootViewController — and from there, as I said in the previous section, we can navigate the view controller hierarchy and the view hierarchy.

You, too, can make your own objects globally visible by attaching them to a globally visible object. A public property of the app delegate, which you are free to create, is globally visible by virtue of the app delegate being globally visible (by virtue of the shared application being globally visible).

Another globally visible object is the shared defaults object obtained by calling [NSUserDefaults standardUserDefaults]. This object is the gateway to storage and retrieval of user defaults, which is similar to a dictionary (a collection of values named by keys). The user defaults are automatically saved when your application quits and are automatically available when your application is launched again later, so they are one of the ways in which your app maintains information between launches. But, being globally visible, they are also a conduit for communicating values within your app.

For example, in one of my apps there’s a setting I call @"hazyStripy". This determines whether a certain visible interface object is drawn with a hazy fill or a stripy fill. This is a setting that the user can change, so there is a preferences interface allowing the user to make this change. When the user displays this preferences interface, I examine the @"hazyStripy" setting in the user defaults to configure the interface to reflect it; if the user interacts with the preferences interface to change the @"hazyStripy" setting, I respond by changing the actual @"hazyStripy" setting in the user defaults.

But the preferences interface is not the only object that uses the @"hazyStripy" setting in the user defaults; the drawing code that actually draws the hazy-or-stripy-filled object also uses it, so as to know which way to draw itself. Thus there is no need for the object that draws the hazy-or-stripy-filled object and the object that manages the preferences interface to be able to see one another! They can both see this common object, the @"hazyStripy" user default (Figure 13-1). Indeed, it is not uncommon to “misuse” the user defaults storage to hold information that is not used to maintain user preferences, but is placed there just because this is a location globally visible to all objects.

The global visibility of user defaults

Figure 13-1. The global visibility of user defaults


Notifications (Chapter 11) can be a way to communicate between objects that are conceptually distant from one another without bothering to provide any way for one to see the other. All they really need to have in common is a knowledge of the name of the notification. Every object can see the notification center, so every object can arrange to post or receive a notification.

Using a notification in this way may seem lazy, an evasion of your responsibility to architect your objects sensibly. But sometimes one object doesn’t need to know, and indeed shouldn’t know, what object (or objects) it is sending a message to.

I gave an example in Chapter 11. Here’s another. In one of my apps, the app delegate may detect a need to tear down the interface and build it back up again from scratch. If this is to happen without causing memory leaks (and all sorts of other havoc), every view controller that is currently running a repeating NSTimer needs to invalidate that timer (Chapter 12). Rather than my having to work out what view controllers those might be, and endowing every view controller with a method that can be called, I simply have the app delegate shout “Everybody stop timers!” — by posting a notification. My view controllers that run timers have all registered for this notification, and they know what to do when they receive it.

Key–Value Observing

Key–value observing, or KVO, is a mechanism that allows one object to be registered with a second object so as to be notified automatically when a value in the second object changes. In order to perform the act of registration, this requires that at some point the second object must be visible to the first (or that they both be visible to some third object). But thereafter, the second object is able to send messages to the first object without an instance variable referring to the first object and without having any knowledge of the first object’s class or publicly declared methods. Architecturally, this is somewhat like the target–action mechanism (Chapter 11), but it works for any two objects. (The KVO mechanism is provided through an informal protocol, NSKeyValueObserving, which is actually a set of categories on NSObject and other classes.) The second object needn’t be an instance of your own class; it can be a built-in Cocoa class. The first object, however, must contain your own code, in order to respond when a notification arrives.


OS X bindings don’t exist on iOS, but you can sometimes use KVO to achieve similar aims.

KVO can be broken down into three stages:


To hear about a change in a value belonging to Object A, Object B must be registered with Object A.


The change takes place in the value belonging to Object A, and it must take place in a special way — a KVO compliant way. Typically, this means using a key–value coding compliant accessor to make the change. (If Object A is of your own class, you can optionally write code that will manually cause other kinds of change to count as KVO compliant.)


Object B is automatically notified that the value in Object A has changed and can react as desired.

Here’s a simple complete example — a rather silly example, but sufficient to demonstrate the KVO mechanism in action. We have a class MyClass1; this will be the class of objectA. We also have a class MyClass2; this will be the class of objectB. Having obtained references to these objects, we register objectB to hear about changes in an instance variable of objectA called value, and then change value. Sure enough, objectB is automatically notified of the change:

// MyClass1.h:

@interface MyClass1 : NSObject

@property (nonatomic, copy) NSString* value;


// MyClass2.m:

- (void) observeValueForKeyPath:(NSString *)keyPath


change:(NSDictionary *)change

context:(void *)context {

NSLog(@"I heard about the change!");


// Somewhere else entirely:

MyClass1* objectA = [MyClass1 new];

MyClass2* objectB = [MyClass2 new];

// register for KVO

[objectA addObserver:objectB forKeyPath:@"value" options:0 context:nil]; 1

// change the value in a KVO compliant way

objectA.value = @"Hello, world!"; 2

// result: objectB's observeValueForKeyPath:... is called 3


We call addObserver:forKeyPath:options:context: to register objectB to hear about changes in objectA’s value. We didn’t use the options: or context: parameters for anything; I’ll talk about the options: parameter in a moment. (The context: parameter is for handing in a value that will come back as part of the notification; see Chapter 12.)

In real life, it would probably be Object B that would register itself to hear about changes in a key path of Object A. I’ve arranged things in an artificial way just to keep the code as simple as possible.


We change objectA’s value, and we do it in a KVO compliant way, namely, by passing through the setter (because setting a property is equivalent to passing through the setter). This is another reason why, as I said in Chapter 12, accessors (and properties) are a good thing: they help you guarantee KVO compliance when changing a value.


When we change objectA’s value, the third stage takes place automatically: a call is made to objectB’s observeValueForKeyPath:.... We have implemented this method in MyClass2 in order to receive the notification. In this simple example, we expect to receive only one notification, so we just log to indicate that we did indeed receive it. In real life, where a single object might be registered to receive more than one KVO notification, you’d use the incoming parameters to distinguish between different notifications and decide what to do.

At the very least, you’ll probably want to know, when observeValueForKeyPath:... is called, what the new value is. We can find that out easily, because we are handed a reference to the object that changed, along with the key path for the value within that object. Thus we can use KVC to query the changed object in the most general way:

- (void) observeValueForKeyPath:(NSString *)keyPath


change:(NSDictionary *)change

context:(void *)context {

id newValue = [object valueForKeyPath:keyPath];

NSLog(@"The key path %@ changed to %@", keyPath, newValue);


It is also possible to request that the new value be included as part of the notification. This depends upon the options: argument passed with the original registration. Here, we’ll request that both the old and new values be included with the notification:

objectA.value = @"Hello";

[objectA addObserver:objectB forKeyPath:@"value"

options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld

context: nil];

objectA.value = @"Goodbye"; // notification is triggered

When we receive the notification, we fetch the old and new values out of the change dictionary:

- (void) observeValueForKeyPath:(NSString *)keyPath


change:(NSDictionary *)change

context:(void *)context {

id newValue = change[NSKeyValueChangeNewKey];

id oldValue = change[NSKeyValueChangeOldKey];

NSLog(@"The key path %@ changed from %@ to %@",

keyPath, oldValue, newValue);


No memory management happens as part of the registration process, so it is incumbent upon you to unregister Object B before it is destroyed; otherwise, Object A may later attempt to send a notification to a dangling pointer (see Chapter 12). This is done by sending Object A theremoveObserver:forKeyPath: message. You must explicitly unregister the observer for every key path for which it is registered; you can’t use nil as the second argument to mean “all key paths”. In real life, where Object B probably registered itself with Object A, it will also be Object B that will unregister itself with Object A, perhaps in its dealloc implementation. Notice that this requires that Object B have a reference to Object A.

Object B should also unregister itself from Object A if Object A is about to go out of existence! This requirement seems onerous, and I’m unclear on the reason for it; it appears to have something to do with memory management of the internal mechanism that makes KVO work. Fortunately, the runtime will send you a nice warning in the log if an object being observed under KVO goes out of existence. (But you get no warning if an observer object goes out of existence; you’ll find out about this only when a message is sent through a dangling pointer and your app crashes.)

Beginners are often confused about how to use KVO to observe changes to a mutable array, to be notified when an object is added to, removed from, or replaced within the array. You can’t add an observer to an array itself; you have to observe through an object that has a key path to the array (through accessors, for example). The simple-minded solution is then to access the array using mutableArrayValueForKey:, which provides an observable proxy object.

For example, as in Chapter 12, let’s posit an object with a property theData which is an array of dictionaries:



description = "The one with glasses.";

name = Manny;



description = "Looks a little like Governor Dewey.";

name = Moe;



description = "The one without a mustache.";

name = Jack;



Suppose this is an NSMutableArray. Then we can register with our object to observe the key path @"theData":

[objectA addObserver:objectB forKeyPath:@"theData" options:0 context:nil];

Now Object B will be notified of changes to this mutable array, but only if those changes are performed through the mutableArrayValueForKey: proxy object:

[[objectA mutableArrayValueForKeyPath:@"theData"] removeObjectAtIndex:0];

// notification is triggered

But it seems onerous to require clients to know that they must call mutableArrayValueForKey:. The simple solution is for our Object A itself to provide a getter that calls mutableArrayValueForKey:. Here’s a possible implementation:

// MyClass1.h:

@interface MyClass1 : NSObject

@property (nonatomic, strong, getter=theDataGetter) NSMutableArray* theData;


// MyClass1.m:

- (NSMutableArray*) theDataGetter {

return [self mutableArrayValueForKey:@"theData"];


The result is that, as far as any client knows, this object has a key @"theData" and a property theData, and we can register to observe with the key and then access the mutable array through the property:

[objectA addObserver:objectB forKeyPath:@"theData"

options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld


[objectA.theData removeObjectAtIndex:0]; // notification is triggered

If you’re going to take this approach, you should really also implement (in MyClass1) the four KVC compliance methods for a mutable array façade (see Chapter 12). Although things will appear to work just fine without them, and although they appear trivial (they are merely delegating toself->_theData the equivalent calls), they will be called by the vended proxy object, which increases its efficiency (and, some would argue, its safety). Without these methods, the proxy object resorts to setting the instance variable directly, replacing the entire mutable array, every time a client changes the mutable array:

- (NSUInteger) countOfTheData {

return [self->_theData count];


- (id) objectInTheDataAtIndex: (NSUInteger) ix {

return self->_theData[ix];


- (void) insertObject: (id) val inTheDataAtIndex: (NSUInteger) ix {

[self->_theData insertObject:val atIndex:ix];


- (void) removeObjectFromTheDataAtIndex: (NSUInteger) ix {

[self->_theData removeObjectAtIndex: ix];


If what you want to observe are mutations within an individual element of an array, things are more complicated. Suppose our array of dictionaries is an array of mutable dictionaries. To observe changes to the value of the @"description" key of any dictionary in the array, you’d need to register for that key with each dictionary in the array, separately. You can do that efficiently with NSArray’s instance method addObserver:toObjectsAtIndexes:forKeyPath:options:context:, but if the array itself is mutable then you’re also going to have to register for that key with any new dictionaries that are subsequently added to the array (and unregister when a dictionary is removed from the array). It sounds daunting, and it is.

The properties of Apple’s built-in classes are typically KVO compliant. Indeed, so are many classes that don’t use properties per se; for example, NSUserDefaults is KVO compliant. Unfortunately, Apple warns that undocumented KVO compliance can’t necessarily be counted on.

On the other hand, some Cocoa classes explicitly invite the use of KVO; they treat it as a primary notification mechanism, instead of the notification center and NSNotification. For example, the AVPlayer class, which plays media, such as movies, has various properties, such as status andrate, that report whether the media is ready to play and whether it is in fact playing. Apple’s AV Foundation Programming Guide states that to monitor an AVPlayer’s playback, you should use key–value observing on its properties.

Key–value observing is a deep mechanism; consult Apple’s Key-Value Observing Guide for full information. It does have some unfortunate shortcomings. For one thing, it’s a pity that all notifications arrive by calling the same bottleneck method, observeValueForKeyPath:.... And keeping track of who’s observing whom, and making sure both observer and observed have appropriate lifetimes and that the observer is unregistered before one of them goes out of existence, can be tricky. But in general, KVO is useful for keeping values coordinated in different objects.


In Apple’s documentation and elsewhere, you’ll find references to the term model–view–controller, or MVC. This refers to an architectural goal of maintaining a distinction between three functional aspects of a program that lets the user view and edit information — meaning, in effect, a program with a graphical user interface. The notion goes back to the days of Smalltalk, and much has been written about it since then, but informally, here’s what the terms mean:


The data and its management, often referred to as the program’s “business logic,” the hard-core stuff that the program is really all about.


What the user sees and interacts with.


The mediation between the model and the view.

Consider, for example, a game where the current score is displayed to the user:

§ A UILabel that shows the user the current score for the game in progress is view; it is effectively nothing but a pixel-maker, and its business is to know how to draw itself. The knowledge of what it should draw — the score, and the fact that this is a score — lies elsewhere.

A rookie programmer might try to use the score displayed by the UILabel as the actual score: to increment the score, read the UILabel’s string, turn that string into a number, increment the number, turn the number back into a string, and present that string in place of the previous string. That is a gross violation of the MVC philosophy. The view presented to the user should reflect the score; it should not store the score.

§ The score is data being maintained internally; it is model. It could be as simple as an instance variable along with a public increment method or as complicated as a Score object with a raft of methods.

The score is numeric, whereas a UILabel displays a string; this alone is enough to show that the view and the model are naturally different.

§ Telling the score when to change, and causing the updated score to be reflected in the user interface, is the work of the controller. This will be particularly clear if we imagine that the model’s numeric score needs to be transformed in some way for presentation to the user.

For example, suppose the UILabel that presents the score reads: “Your current score is 20”. The model is presumably storing and providing the number 20, so what’s the source of the phrase “Your current score is…”? Whoever is deciding that this phrase should precede the score in the presentation of the score to the user, and is making it so, is a controller.


Figure 13-2. Model–view–controller

Even this simplistic example (Figure 13-2) illustrates very well the advantages of MVC. By separating powers in this way, we allow the aspects of the program to evolve with a great degree of independence. Do you want a different font and size in the presentation of the score? Change the view; the model and controller need know nothing about it, but will just go on working exactly as they did before. Do you want to change the phrase that precedes the score? Change the controller; the model and view are unchanged.

Adherence to MVC is particularly appropriate in a Cocoa app, because Cocoa itself adheres to it. The very names of Cocoa classes reveal the MVC philosophy that underlies them. A UIView is a view. A UIViewController is a controller; its purpose is to embody the logic that tells the view what to display. In Chapter 11 we saw that a UIPickerView does not hold the data it displays; it gets that data from a data source. So the UIPickerView is a view; the data source is model.

A further distinction, found in Apple’s documentation, is this: true model material and true view material should be quite reusable, in the sense that they can be transferred wholesale into some other app; controller material is generally not reusable, because it is concerned with how this app mediates between the model and the view.

In one of my own apps, for example, we download an XML (RSS) news feed and present the article titles to the user as a table. The storage and parsing of the XML are pure model material, and are so reusable that I didn’t even write this part of the code (I used some code called FeedParser, by Kevin Ballard). The table is a UITableView, which is obviously reusable, seeing as I obtained it directly from Cocoa. But when the UITableView turns to my code and asks what to display in this cell, and my code turns to the XML and asks for the title of the article corresponding to this row of the table, that’s controller code.

MVC helps to provide answers about what objects need to be able to see what other objects in your app. A controller object will usually need to see a model object and a view object. A model object, or a group of model objects, usually won’t need to see outside itself. A view object typically doesn’t need to see outside itself specifically, but structural devices such as delegation, data source, and target–action allow a view object to communicate agnostically with a controller.