I'm creating an interactive book for learning languages. It has reading, quiz and some simple game. The content of each chapter is an HTML file. The book allows the user to learn about 300 words that exist in the text. Earch word was enclosed in a link like this: < a href="word">word< /a> when the user touch the link, a modal view appears with the translation and information about that word.
This is the code I'm using to get the link:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
// currentWord is the word in the link
self.currentWord = [[request URL] lastPathComponent];
// okToCatchLinks is a BOOL that I use to avoid showing the modalview when the page
// is loaded for the first time.
if (okToCatchLinks){
NSLog(#"Ok to catch links!");
WordViewController *viewController = [[WordViewController alloc] initWithNibName:#"WordViewController" bundle:nil]
// I did my homework creating the delegate protocol to dismiss the modal view.
viewController.delegate = self;
// This is a label in the modalview showing the word in the HTML link.
viewController.labelTitle = self.currentWord;
// Create a Navigation controller to add the "DONE" dismiss button
UINavigationController *navController = [[UINavigationController alloc]
initWithRootViewController:viewController];
navController.modalPresentationStyle = UIModalPresentationFormSheet;
navController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
// show the navigation controller modally
[self presentModalViewController:navController animated:YES];
// Clean up resources
[navController release];
[viewController release];
}
okToCatchLinks = YES;
return YES;
}
With this code I will get the selected word in a string variable. Then I search that word in the DB using CoreData.
The HTML is UTF-8 encoded. I have to be able to search for that word in different languages. So if the user click on the word (日本語) or (résumé) I have to be able to find it in the DB.
For the data store I converted an CSV file to a .sqlite file.
I wonder if there is a better way to do this. Personally I don't like to use < a href=""> to get the link, but I couldn't find any other way to get the current word in a link. Also performing the search of that word in the DB is not clean, because I'm not using any UID for each row. I just compare the string holding the word with the words in the corresponding column of the DB.
Is there a more efficient way to do this?
To resume: Having a list of words, mark those words in the HTML so the user can touch and retrieve information about that word from a DB.
Some observations:
UIDs: As long as your words are unique, you can use that column as the primary key without using a separate UID. Actually, Core Data will create one for you anyway, so you can use objectWithID to retrieve your word.
HTML Links: Your solution with UIWebView, HTML files and links seems feasible to me. However, you could of course also use a UITextView and handle the selections programmatically, working with NSRange. That would perhaps be more complicated, but also more "native".
Delegate: You only need a delegate if you want to pass information back to the view that first presented the model view controller (too much homework! ;-)). Just dismiss it from within with
[self dismissModalViewControllerAnimated:YES];
Related
When using UIDocumentPickerViewController for importing data into my app, I would like to remember the last service/location that was chosen by the user, and start the navigation with that service.
E.g. if a user imports something from Dropbox, and then later on wants to import something again, I would like the document picker to start with Dropbox as the initial location.
Unfortunately, the default behaviour is that the picker always starts with iCloud Drive, so each time a user wants to import something from Dropbox, they have to tap on Locations, and pick Dropbox from there - two unnecessary taps.
I've tried to keep a strong reference to a previously shown picker, but presenting that picker again doesn't seem to work - it just shows a blank view.
if(self.documentPicker) {
[self presentViewController:self.documentPicker animated:YES completion:nil];
return;
}
UIDocumentPickerViewController *vc =
[[UIDocumentPickerViewController alloc] initWithDocumentTypes:#[#"public.audio"] inMode:UIDocumentPickerModeImport];
vc.delegate = self;
self.documentPicker = vc;
[self presentViewController:vc animated:YES completion:nil];
There's also UIDocumentMenuViewController, which lets you choose a location/service up front and lets you then show the document picker which was chosen by it, but again, I have found no way to store a reference to a location with which to show a document picker in future import actions.
cheers!
I have searched for an entire day for a simple example on this and haven't found it yet. I am working on an app and I want to make an API call on the initial load and populate some variables that will be accessible in any of the tab views.
Example: I want to make a single API call to get my data which will include data relating to alerts for the alerts tab. I want to use this data on the initial load to update the "Alerts" tab badge. However, I want to also use that information on the alerts page once the person goes to that tab without having to make another API call to get the same information again.
I have read a ton of explanations that do not fit my requirements, so I am looking for a good example to help me out.
Use your UITabBarViewController's viewControllers property to access the array of view controllers in your tab bar controller. Typecast them according to your architecture of tab bar controller.
Then get a pointer to any of view controller using that array.
For example, say your tab bar controller has 5 tabs, each tab having a UINavigationController which has particular UIViewController as root view controllers. Say you want to set badge value of 3rd tab to your web response array count. You can do that as
[[[self.tabviewController viewControllers] objectAtIndex:2]
setBadgeValue:[NSString stringWithFormat:#"%d",[myArray count]];
You can also get to particular view controller's property by typecasting the view controllers. For example
MyViewController *myVc = (MyViewController*) [[(UINavigationController*)[[self.tabviewController viewControllers] objectAtIndex:2] viewControllers] objectAtIndex:0];
[myVc setPropertyName:propertyValue];
I had this question typed up since yesterday and made sure to search before posting. There was no question similar that I found that had the answer, and it may be very straight forward or maybe this is not the way to do it but here is how I solved this issue: using NSUserDefaults and the code example on this page
Put the data in your app delegate object. You can access it from anywhere in your app by (MyAppDelegate *)[[UIApplication sharedApplication] delegate], or you can give each of your view controllers an explicit link to it.
NSUserDefaults isn't really meant for sharing data globally in your app, although it would get the job done. It also has the benefit that the information sticks around if your app can't connect to the server next time. Is that a good thing or a bad thing?
Put all of those variables in a single class and access a shared instance of it whenever you want.
Add
+ (YourClass *)sharedObject
{
static YourClass *sharedClassObject = nil;
if (sharedClassObject == nil) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedClassObject = [[YourClass alloc] init];
//Initialise it here if necessary
});
}
return sharedClassObject;
}
To access the shared instance, simply use [YourClass sharedObject].
You should use NSNotificationCenter to post the notification that new data arrived and your new data as an object.
Each of the viewControllers that need that object should just subscribe to that notification and just consume the new data.
It seems like I am not able to change the title on the navigation bar, which gets set to the Subject of the email (in this case "My Subject"). In this case I'd like to get rid of the title, either using an empty string as title or rendering the title invisible.
MFMailComposeViewController *mfViewController = [[MFMailComposeViewController alloc] init];
mfViewController.mailComposeDelegate = self;
[mfViewController setSubject:[NSString stringWithFormat:#"My Subject"]];
[mfViewController setMessageBody:[self emailBody] isHTML:NO];
[mfViewController setTitle:#""];
where u have presented ModalViewController
[self presentModalViewController:controller animated:YES]; // Existing line
add
[[[[controller viewControllers] lastObject] navigationItem] setTitle:#"Set the title"];
I believe this is some kind of protection came with iOS4.
It is clearly stated here that you MUST NOT change the interface provided by Apple.
http://developer.apple.com/library/ios/#documentation/MessageUI/Reference/MFMailComposeViewController_class/Reference/Reference.html
Important: The mail composition interface itself is not customizable and must not be modified by your application. In addition, after presenting the interface, your application is not allowed to make further changes to the email content. The user may still edit the content using the interface, but programmatic changes are ignored. Thus, you must set the values of content fields before presenting the interface.
i have searched the forums and some have got their app rejected, so i guess u should refrain urself from doing this.
hope it helps. happy coding :)
I'm in need of some detail. I've looked through multiple books/forums, and I've tried as best as I can on my own. However, at this point I'm in need of some outside help with simple directions, if at all possible. I'm trying to make this as easy as possible to get the goal across, and if you need anything, just ask.
So, here is what I'm trying to do:
What I have:
I currently have the WebView view, and the bookmarks view with a table in it. I have NSUserDefaults passing the current URL to the bookmarks view and displaying it (but not saving it)
What the goal is:
I need to add an "Add Bookmarks" button underneath the rest of the table that gets the current string of the WebView in the other view and saves it as an entry to the table.
What I need:
So, at this point (as a start) I need a method of getting the URL of the WebView from the other view and transferring it to the bookmarks view to be saved as a row to the table.
I was thinking of doing this by calling absoluteString and saving to user defaults, but I need assistance for the code portion. I don't know the full usage of NSUserDefaults yet, but I do have some experience with it.
Thanks for the help! It's greatly appreciated!
Jake
You should pass the current URL and Title to the Bookmarks view before you open it:
[bookmarks setUrl:webView.request.URL.absoluteString];
[bookmarks setTitle:[webView stringByEvaluatingJavaScriptFromString:#"document.title"]];
... open bookmark view now ...
A full example would be:
- (IBAction)bookmarksPressed:(id)sender {
// Open the book marks controller passing it the current URL and Title
BookmarksViewController * bookmarksViewController = [[[BookmarksViewController alloc] initWithNibName:#"BookmarksViewController" bundle:nil] autorelease];
[bookmarksViewController setUrl:webView.request.URL.absoluteString];
[bookmarksViewController setTitle:[webView stringByEvaluatingJavaScriptFromString:#"document.title"]];
[self presentModalViewController: bookmarksViewController animated:YES];
}
I am currently in a project creating an iPad book. Unfortunately, since this is my first iPad project I am coding in a very unconventional style.
This is a 20 page book and I have 20 XIBs. On each XIB I am calling the next XIB, but my fear is that the current XIB isn't getting unloaded and still is taking up memory. When I am about on page 10 or so, the app will crash due to didReceiveMemoryWarning.
I am switching views using 2 different methods (I don't know which one will better suit my purpose):
#METHOD 1
-(IBAction)NextPage:(id)sender
{
nextPage = [[NextPage alloc] initWithNibName:#"NextPage" bundle:nil];
[self.view addSubview:nextPage.view];
[self presentModalViewController:nextPage animated:YES];
[self.view release]; // this was added to hopefully release the current view.
}
#METHOD 2
-(IBAction)NextPage:(id)sender
{
NextPage *nextpage = [[[NextPage alloc] init] autorelease];
[self presentModalViewController:nextpage animated:YES];
}
Each view has buttons and stuff, but I want to make sure I complete erase them from memory on each page call.
I used dealloc to try to remove the view, but when I check for memory leaks and go back and forth between pages, the memory crawls up.
- (void)dealloc {
[view release]; // don't know which is which
[self.view release]; // is this correct?
[super dealloc];
}
Any help is appreciated! Thanks in advance.
If you're just switching between pages in a book, you probably shouldn't be presenting modally. Instead, you could just swap out views.
http://developer.apple.com/library/ios/#documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/CreatingViews/CreatingViews.html
... transitionFromView:toView:duration:options:completion: methods to
swap out entire sets of views for new ones.
http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIView_Class/UIView/UIView.html#//apple_ref/occ/clm/UIView/transitionFromView:toView:duration:options:completion:
Another option would be to use layers within a view.
http://www.raywenderlich.com/2502/introduction-to-calayers-tutorial
If you present the next page modally (as you are doing), the current page won't be released. Instead, set your window's rootViewController to the new page.
UINavigationController could handle this much more simply. Take a look at the documentation. Also, as of iOS5 there is now a book type viewController that may serve you well.