I am writing an app which is a sort of dictionary – it presents the user with a list of terms, and when clicked on, pops up a dialog box containing the definition. The definition itself may also contain terms, which in turn the user can click on to launch another definition popup.
My main app is stored in ‘myViewController.m’. It calls a custom UIView class, ‘CustomUIView.m’ to display the definition (this is the dialog box that pops up). This all works fine.
The text links from the CustomUIView then should be able to launch more definitions. When text is tapped in my CustomUIView, it launches another CustomUIView. The problem is, that this new CustomUIView doesn’t have access to the hash map which contains all my dictionary’s terms and definitions; this is only available to my main app, ‘myViewController.m’.
Somehow, I need to make my hash map, dictionaryHashMap, visible to every instance of the CustomUIView class. dictionaryHashMap is created in myViewController.m when the app opens and doesn’t change thereafter.
I don’t wish to limit the number of CustomUIViews that can be opened at the same time (I have my reasons for doing this!), so it would be a little resource intensive to send a copy of the dictionaryHashMap to every instance of the CustomUIView. Presumably, the solution is to make dictionaryHashMap a global variable.
Some of my code:
From myViewController.m:
- (void)viewDidLoad
{
self.dictionaryHashMap = [[NSMutableDictionary alloc] init]; // initialise the dictionary hash map
//... {Code to populate dictionaryHashMap}
}
// Method to pop up a definition dialog
- (void)displayDefinition:(NSString *) term
{
NSArray* definition = [self.dictionaryHashMap objectForKey:term]; // get the definition that corresponds to the term
CustomUIView* definitionPopup = [[[CustomUIView alloc] init] autorelease]; // initialise a custom popup
[definitionPopup setTitle: term];
[definitionPopup setMessage: definition];
[definitionPopup show];
}
// Delegation for sending URL presses in CustomUIView to popupDefinition
#pragma mark - CustomUIViewDelegate
+ (void)termTextClickedOn:(CustomUIView *)customView didSelectTerm:(NSString *)term
{
myViewController *t = [[myViewController alloc] init]; // TODO: This instance has no idea what the NSDictionary is
[t displayDefinition:term];
}
From CustomUIView.m:
// Intercept clicks on links in UIWebView object
- (BOOL)webView: (UIWebView*)webView shouldStartLoadWithRequest: (NSURLRequest*)request navigationType: (UIWebViewNavigationType)navigationType {
if ( navigationType == UIWebViewNavigationTypeLinkClicked ) {
[myViewController termTextClickedOn:self didSelectTerm:request];
return NO;
}
return YES;
}
Any tips on how to make the dictionaryHashMap visible to CustomUIView would be much appreciated.
I have tried making the dictionaryHashMap global by doing the following:
- Changing all instances of ‘self.dictionaryHashMap’ to ‘dictionaryHashMap’
- Adding the line ‘extern NSMutableDictionary *dictionaryHashMap;’ to CustomUIView.h
- Adding the following outside of my implementation in myViewController.m: ‘NSMutableDictionary *dictionaryHashMap = nil;’
However, the dictionaryHashMap remains invisible to CustomUIView. As far as I can tell, it actually remains a variable which is local to myViewController…
It’s not resource-intensive to pass around the reference (pointer) to
dictionaryHashMap. A pointer to an object is only 4 bytes. You could just pass it from your view controller to your view.But I don’t know why you even need to do that. Your view is sending a message (
termTextClickedOn:didSelectTerm:) to the view controller when a term is clicked. And the view controller already has a reference to the dictionary, so it can handle the lookup. Why does the view also need a reference to the dictionary?Anyway, if you want to make the dictionary a global, it would be more appropriate to initialize it in your app delegate, in
application:didFinishLaunchingWithOptions:. You could even make the dictionary be a property of your app delegate and initialize it lazily.UPDATE
I didn’t notice until your comment that
termTextClickedOn:didSelectTerm:is a class method. I assumed it was an instance method becausemyViewControllerstarts with a lower-case letter, and the convention in iOS programming is that classes start with capital letters. (You make it easier to get good help when you follow the conventions!)Here’s what I’d recommend. First, rename
myViewControllertoMyViewController(or better,DefinitionViewController).Give it a property that references the dictionary. Whatever code creates a new instance of
MyViewControlleris responsible for setting this property.Give
CustomUIViewproperties for a target and an action:Set those properties when you create the view:
In the view’s
webView:shouldStartLoadWithRequest:method, extract the term from the URL request and send it to the target/action:In the view controller’s
termWasClicked:method, create the new view controller and set its dictionary property: