xcode page-based application - objective-c

I am trying to create an app based on the page-based application template in xcode 4, that has a title page, table of contents page, and content pages, all formatted differently. I am new to ios programming, completed the 3 apple tutorials and read a lot of documentation but this is basically my first non-tutorial app.
I'd really appreciate a code example or instructions that shows how to do this properly. This particular template does not seem to have many examples out there.
specifically:
I created a new xcode project and chose the page-based application
template (i'm not including the source code here because it should
be easy to generate for anyone with xcode 4)
The template creates an AppDelegate, a RootViewController, a DataViewController and a ModelController
For now, I don't care about showing dynamic data. I want the first page to show a view with a label that says "Title" and the
second page and after to show a text area filled with lorem ipsum.
I have created a TitlePageView and ChapterView in the storyboard and
corresponding ViewController files, but do not know how to tie them
to the DataViewController so that they display.

Yeah, I'm not sure how to do it using storyboard, but if you want a simple cut-and-paste solution using nibs, I posted one here: https://stackoverflow.com/a/9687639/542400

This is how I ended up putting different views on each page.
Create the views for each page in the storyboard, and leave them without a segue or connection to the main page. (you get yellow warning for this)
Set the 'identifier' property for each new view to some unique string, e.g. "titlePage"
Create an outlet for the big white part of the default page view called "contentArea" in the DataViewController
Update the DataViewController class viewWillAppear method to create your page views and add them as sub-views to the contentArea:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (_contentArea.subviews.count == 0)
{
UIView *pageSubView;
UIViewController *pageSubViewController;
pageSubViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"titlePage"];
[self addChildViewController: pageSubViewController];
[pageSubViewController didMoveToParentViewController:self];
pageSubView = pageSubViewController.view;
[_contentArea addSubview:pageSubView];
CGRect pageViewRect = _contentArea.bounds;
pageSubView.frame = pageViewRect;
}
}

here is the code snippet for creating a page
pageInfoLabel.text = [NSString stringWithFormat:#"Some really useless information on page %d", pageNumber + 1];

Related

iOS7 Keyboard Behavior with SearchBar/UITableView: Offset on secondary view appearances

Problem
I am having a rather big issue with the iOS7 keyboard appearance. I have a Searchbar on a UIViewController with TableView Delegation/Data Source setup (I am using the self.searchDisplayController delegates as well). I segue from this scene to a prototype tableview to show the results.
Here is the issue:
On first load I can see the keyboard being displayed when I tap into the text field of the UISearchBar. I can type and perform a search with the results being shown in the next scene.
I've added NSNotifications to view the keyboard properties in local methods keyboardWillShow and keyboardWasShown. I can see on the first scene appearance (after the view is completely loaded):
I segue to the result tableview at this point and when I navigate back and touch the text field, my keyboard shows up either fully or partially off-screen:
When I look at the keyboardWillShow notification at this point I can see that my keyboard values are incorrect:
I've researched and tried many possibilities including:
Added the following to my main view controller:
-(BOOL)canResignFirstResponder
{
return YES;
}
-(BOOL)canBecomeFirstResponder
{
return YES;
}
Configured the following in my view did load
self.searchDisplayController.searchBar.spellCheckingType = UITextSpellCheckingTypeNo;
self.searchDisplayController.searchBar.autocapitalizationType= UITextAutocapitalizationTypeNone;
self.searchDisplayController.searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
self.searchDisplayController.searchBar.keyboardType = UIKeyboardTypeDefault;
Put in standard stubs for:
-(void)searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)tableView
-(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
I've noticed that if I choose a Partial Curl as my segue mode, the keyboard remains accessible when I roll back to the main view controller (but then it was never fully off screen in that case). However if I move from the results tableview to a detail scene and then navigate back to the main view controller, the keyboard appears off-screen again.
Question
Is there a method I can use to intercept the misplaced keyboard so that it displays in the default location?
NB: Along these lines, I have created a NSDictionary property to hold the initial userInfo values with the correct keyboard placement. I am not sure how to reassign these values to get the keyboard to return to it's original placement.
BTW - This seems a bit of a hack to get the keyboard fixed due to a bug in IB, is there some other way that I can try to remedy the situation?
Thanks in advance for any feedback!
Solution
This was such an obscure issue that I'm sharing the solution to save the next person some effort. Like most programming issues, it turns out this one was self-inflicted. In my original iteration of this project I had turned off rotational support as I am learning auto-layout and I wanted to ease into the transition from Springs and Struts. Somehow between the start of the project and the code release I ended up with this bit of code in the Main Scenes' View Controller.
//BAD
- (NSUInteger) supportedInterfaceOrientations
{
return !UIInterfaceOrientationPortraitUpsideDown;
}
instead of returning a valid enumeration like...
//OK
- (NSUInteger) supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}

Reloading UICollectionView causing flickering

I have subclassed a CollectionView and using it using to display a collection of images in different categories. For example: Most Popular, Most Viewed. I access each category/page through a TabbarController.
The classes I have are:
Main class - MediaList - Base class for fetching and displaying media in a collection view depending on what type of media is requested.
SubClasses - MostPopular and MostViewed are both very light classes that inherit from the main class.
The problem is that when I move from MostPopular to MostViewed, the collection view initially displays the last category of pictures and then refreshes to the new...As a result you see a flicking effect.
Sample code from MediaList
- (void)viewDidLoad
{
[super viewDidLoad];
self.mediaCollection.dataSource = self;
self.mediaCollection.delegate = self;
[self getMedia];
}
(void) getMedia
{
NSLog(#"///////////////////////// GETTING MEDIA /////////////////////////");
XMLGenerator * sharedXmlGen = [XMLGenerator sharedXmlGenerator];
GlobalVars * sharedGlobalVars = [GlobalVars sharedGlobalVars];
sharedXmlGen.assetFlag = _contentFilter;
NSLog(#"The filter is: %#", _contentFilter);
[sharedXmlGen getPhotoVideoWithCallBackFunction:^{
[_mediaCollection performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
}];
}
Sample code from SubClass (MostPopular):
- (void)viewDidLoad
{
[super setContentFilter:FILTER_POPULAR]; //Set the filter for the type of content
[super viewDidLoad];
// Do any additional setup after loading the view.
}
Two clarifications:
I should add that I am trying to re-use as much code as possible without having to create new views on the storyboard or controllers.
Because the media returned is very dynamic and can be updated regularly, I have had to reload my data (using getMedia) on viewDidAppear. This now means each selection of a particular page will result in the flickering when the new view is loaded...
Updates
- After further investigation it looks like this has nothing to do with subclassing the uicollectionview. The issue instead is just reloading data into the uicollectionview. To be sure, I just clicked on one of the two subclassed views. I also added a reload method to the viewdidAppear method just to see the issue get even worse. It's also much easier to see that the issue is that last set of images in the collection view initially displays the last category of pictures before the new one refreshes. Then once the collection is refreshed I get the flicker.
*Updates Oct 4 *
Starting to think my best solution is to display a waiting indicator and block the page while loading. I did try setting the uicollectionview to nil, and believe that will solve the problem as well, but not sure it will be straightforward to reset.
Although it may not be immediately apparent in the code above the root cause was actually the getMedia call. All of the subclassing etc. works perfectly fine.
Specifically having the reload method in the getMedia call and was creating the issue.
[_mediaCollection performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];

xCode pass data between dynamically created ViewControllers

I am trying to set up a project which dynamically creates ViewControllers based off a JSON file. I asked a question the other day about how to create this here
xCode Dynamically create ViewControllers
So I have been able to create the ViewControllers dynamically and after playing around with it more, I have been quite easily set it up so when the app loads, it generates how ever many numbers of ViewControllers is specified in the JSON. I can also navigate between them easy enough and also have each screen set up buttons, views etc from the JSON. I do this simply by doing
NSDictionary *MainJSON = [sJson JSONValue];
NSArray *theArray = [MainJSON valueForKey:#"viewControllers"];
Then loop through theArray creating a ViewController instance.
My problem is, I want to be able to pass data between the ViewControllers. So say for example I set it up in the JSON so the first ViewController has a text field. The user will enter some data and I want to be able to set it up so when they navigate to the next screen, that data is carried to the next screen. I currently switch screens like this
-(void)nextScreen
{
for(int i = 0; i < [vcArray count]; i++)
{
int iID = i+1;
if([self.navigationController.viewControllers count] == iID)
{
ViewController *theVC = [vcArray objectAtIndex:i];
[self.navigationController pushViewController:theVC animated:YES];
break;
}
}
}
Now usually each ViewController would have a class, so in the ViewController I am pushing I can do property and synthesise a NSString in that class, so when passing data to the next ViewController, I would just do this.
vc.theString = textField.text
But as I am dynamically generating these ViewControllers, I can't do this as I am only using one .h and .m file and each ViewController I generate is using the same XIB file. Does anyone have any ideas of how I could go about passing data in this set up?
If your problem is that you need different xib for same view controller, you can supply all of them in the main iOS app, later by passing xib name in JSON you can instantiate that xib and assign to the controller.
If you also need to recall UIView objects you don't know by name, you can always use the tag attribute stored in JSON as well.
Maybe you can also store the UIView type, such as 'UILabel', 'UITextView', ecc... and call appropriate setter for value.
Figured it out. If I give each view a tag from the JSON, can easily connect up the objects I need.

Showing a different XIB/NIB in an iOS app

I have multiple nib (xib) files and I want the user to see a different one when they tap a button. What I am looking for:
- (IBAction)buttonTap {
//Code for showing a different nib goes here
}
I can't figure out how to do this. I can show a different view within the nib file just fine, but I can't get it to show a different nib. How do I show a different nib when the user taps a button?
Any help is appreciated! Thanks!
The way I handle switching between actual xib's, and I'm sure there are a multitude of ways to accomplish the same thing, is to have my App Delegate act as a routing center between my views.
I subscribe my App Delegate to recieve events from button presses for existing views. When it recieves a request to switch views, such as a button press, I do something like this:
- (void) showLogin
{
LoginViewController *loginViewController = [[LoginViewController alloc]
initWithNibName:#"LoginViewController" bundle:nil];
// Show
self.loginViewController = loginViewController;
[loginViewController release];
self.window.rootViewController = self.loginViewController;
}
I set my rootViewController to the view I am attempting to display. It doesn't release the old controller, but simply replaces the view being displayed. You can place more logic in to determine if it's already displayed, close out other views, etc. In most simplistic terms, this works for me.

MKMapView not allowing user interaction on Ipod Touch OS 3.1.3, works correctly on simulator 3.2 / 4.0

I have been coding and testing an app which uses a navigation controller, tab bar and table views together as shown in this tutorial video:
I have also coded a MapView page which shows custom annotations. This seems to work fine in every version of the simulator I have tried it on. This morning I have finally got the app running on my Ipod Touch which runs OS 3.1.3 - everything works as expected except the map does not seem to allow user interaction at all. I cannot tap on annotations, the current location or move and zoom at all.
I have been through all the settings in the Interface Builder for the mapview, and made sure that all the 'User Interaction', 'Allow Multitouch' boxes have been ticked. This doesn't seem to change anything.
Any help greatly appreciated.
The Mapview is put into the view as follows:
// Grab the maps view controller ready for loading
MapView *childController = [[MapView alloc] initWithNibName:#"MapView" bundle:nil];
childController.title = #"View on Map";
// Push the new view controller onto the stack
[self.navigationController pushViewController:childController animated:YES];
[childController release];
childController = nil;
I've also tried running the view in a modal view controller just to see what would happen. The view was shown and any interaction didnt seem to work - with the exception of a small section at the bottom where I made the view itself slightly shorter so it would fit in above the tab bar. This section seems to have another map underneath my view which DOES respond to user interaction. So there is a 1cm or so block which does move - my view seems to stay static on top of it, though.
The view underneath does not appear to have any annotations or the current user location.
Ok I've solved this one:
In the mapview.m file where I set up the view and load the annotations, within the viewDidLoad function I had the following code:
- (void)viewDidLoad {
// More code before this..
[mapView addAnnotations: eventPoints];
// This is causing the problems on the ipod touch.
// The view is added ON TOP of the first map..
//[self.view addSubview:mapView];
self.view = mapView;
// More code after this..
}
Where mapView is
IBOutlet MKMapView *mapView;
Adding a subview on top of the current view didn't want to work. Actually setting the view to be the new updated view with annotations seems to work fine. It's still strange that the simulator would work and not the device in the first place though.
Hope this helps someone.