I'm very new to iOS programming (Coming from Java / C++). I'm trying to set up an app with a TabBarController of which one tab should be a SplitView. I've done my research and I know that UISplitview will not work and everywhere people recommend using the MGSplitViewController. I've looked at the demo but I just can't figure out how to use it without it beeing the app's root view and can't find any sample code that could help
So here is what I do with the classes from the demo in a separate UIViewController class that I afterwards add to the TabBarController: This is my class:
#import <UIKit/UIKit.h>
#import "MGSplitCornersView.h"
#import "RootViewController.h"
#import "DetailViewController.h"
#interface ChannelViewController : UIViewController {
MGSplitViewController *splitViewController;
RootViewController *rootViewController;
DetailViewController *detailViewController;
}
#property (nonatomic, retain) MGSplitViewController *splitViewController;
#property (nonatomic, retain) RootViewController *rootViewController;
#property (nonatomic, retain) DetailViewController *detailViewController;
#end
And this is my desperate try to set it up
- (id)initWithTabBar
{
self = [super init];
//this is the label on the tab button itself
self.title = #"SplitView";
//use whatever image you want and add it to your project
//self.tabBarItem.image = [UIImage imageNamed:#"name_gray.png"];
// set the long name shown in the navigation bar at the top
self.navigationItem.title=#"Nav Title";
self.splitViewController = [[MGSplitViewController alloc] init];
self.rootViewController = [[RootViewController alloc] init];
self.detailViewController = [[DetailViewController alloc] init];
[self.splitViewController setDetailViewController:detailViewController];
[self.splitViewController setMasterViewController:rootViewController];
[self.view addSubview:splitViewController.view];
[self.rootViewController performSelector:#selector(selectFirstRow) withObject:nil afterDelay:0];
[self.detailViewController performSelector:#selector(configureView) withObject:nil afterDelay:0];
if (NO) { // whether to allow dragging the divider to move the split.
splitViewController.splitWidth = 15.0; // make it wide enough to actually drag!
splitViewController.allowsDraggingDivider = YES;
}
return self;
}
I guess I'm doing something wrong with delegates? Or do I have something else mixed up?
Is the demo doing things in the IB that I can't see in the code?
I get the split view but no content and especially no navigation bar with the buttons the demo comes with.
I'd be very thankful for hints or sample code!
Ok manny, here we go. This is my working code for the interface:
#import <UIKit/UIKit.h>
#import "MGSplitViewController.h"
#import "ecbView.h"
#import "ecbCalc.h"
#interface splitMain : MGSplitViewController <UIPopoverControllerDelegate,
MGSplitViewControllerDelegate>
{
IBOutlet UIPopoverController* popoverController;
IBOutlet UINavigationController* naviController;
IBOutlet ecbCalc* viewCalcLeft;
IBOutlet ecbView* euroRatesRight;
UIBarButtonItem* savedButtonItem;
BOOL keepMasterInPortraitMode;
BOOL memoryWasDropped;
BOOL viewLoaded;
}
#property (nonatomic, retain) UIPopoverController* popoverController;
#property (nonatomic, retain) UINavigationController* naviController;
#property (nonatomic, retain) ecbCalc* viewCalcLeft;
#property (nonatomic, retain) ecbView* euroRatesRight;
#property (nonatomic, retain) UIBarButtonItem* savedButtonItem;
#property (nonatomic, readonly) BOOL keepMasterInPortraitMode;
#property (nonatomic, readonly) BOOL memoryWasDropped;
#property (nonatomic, readonly) BOOL viewLoaded;
- (void)dismissPopoverController: (BOOL)animated;
- (void)settingsChanged;
#end
and here excerpts from implementation file:
- (id)initWithCoder:(NSCoder *)aDecoder
{
if ((self = [super initWithCoder:aDecoder]))
{
// my initialization...
}
return self;
}
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView
{
CGRect rectFrame = CGRectMake(0.0, 20.0, 768.0, 1004.0 - 48.0); // being above a tab bar!
viewLoaded = NO;
self.view = [[UIView alloc] initWithFrame:rectFrame];
viewCalcLeft = [[ecbCalc alloc] initWithNibName:#"ecbCalc" bundle:nil];
euroRatesRight = [[ecbView alloc] initWithNibName:#"ecbView-iPad" bundle:nil];
naviController = [[UINavigationController alloc] initWithRootViewController:self.viewCalcLeft];
naviController.navigationBar.barStyle = UIBarStyleBlack;
naviController.title = nil;
viewCalcLeft.title = NSLocalizedString(#"BtnTitleCalc", #"");
viewCalcLeft.view.hidden = NO;
NSUserDefaults* prefs = [NSUserDefaults standardUserDefaults];
if ([prefs objectForKey:#"iPadAlwaysSplitTableView"] != nil)
self.keepMasterInPortraitMode = [prefs boolForKey:#"iPadAlwaysSplitTableView"];
else
self.keepMasterInPortraitMode = YES;
NSArray* theViewControllers = [NSArray arrayWithObjects:self.naviController, self.euroRatesRight, nil];
[self setViewControllers:theViewControllers];
[self setDelegate:self];
[self setShowsMasterInPortrait:keepMasterInPortraitMode];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
// protection because this one is called twice
if (viewLoaded)
return;
[super viewDidLoad];
if (memoryWasDropped)
{
if (!self.keepMasterInPortraitMode && UIInterfaceOrientationIsPortrait(self.interfaceOrientation))
{
// recreate popover controller
self.popoverController = [[UIPopoverController alloc] initWithContentViewController:self.viewCalcLeft];
}
}
viewLoaded = YES;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
memoryWasDropped = YES;
// Release any cached data, images, etc. that aren't in use.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
[self dismissPopoverController:NO];
self.popoverController = nil;
self.naviController = nil;
self.viewCalcLeft = nil;
self.euroRatesRight = nil;
viewLoaded = NO;
}
My MainWindow.xib has a UITabBarController and the button for splitMain is configured for this class but with an empty xib entry. So creation has to go via loadView. Maybe I could have done the viewDidLoad stuff within loadView ... but so I had to protect viewDidLoad from being called twice. That happens in loadView as soon as the view is instantiated from MGSplitViewController class because the initWithCoder there is calling [self setup]. In that function the frame rect is calculated with self.view.bounds so that viewDidLoad is called again because the view doesn't exist yet. Maybe one could implement a workaround within MGSplitViewController.m but I was too lazy doing that.
To get this working on a tab bar controller please make sure you commit most of the changes that are published on the MGSplitViewController's git page. Good luck.
Related
I created a NavigationBar and added it to the UIViewController. But after init, the reference turns to nil. I'm new to iOS and OC, I don't know why. Anyone can help? Thank you.
code summary:
#interface ContainerViewController()
#property (nonatomic, retain) UINavigationBar *nav;
#property (nonatomic, retain) UINavigationItem *navItem;
#end
#implementation ContainerViewController
- (instancetype) initWithParams:(NSDictionary *)params {
self = [super init];
if (self) {//...}
return self;
}
- setNavTitle:(NSDictionary *) params {
NSString *title = params[#"title"];
/////////////////////////////////
// here goes wrong
// self.navItem == nil here, why?
/////////////////////////////////
self.navItem.title = title;
}
- (void) viewWillAppear:(Bool)animated {
[super viewWillAppear:NO];
static float navHeight = 64.0;
UIViewController *wvController = [WebView init here];
UINavigationBar *nav = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), navHeight)];
UINavigationItem *navItem = [[UINavigationItem alloc] initWithTitle:title];
nav.items = [NSArray arrayWithObjects: navItem, nil];
///////////////////////////////
// I saved the reference here
//////////////////////////////
[self setNav:nav];
[self setNavItem:navItem];
[self.view addSubview:nav];
[self addChildViewController:wvController];
wvController.view.bounds = CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds) - navHeight);
[self.view addSubview:wvController.view];
[wvController didMoveToParentViewController:self];
}
#end
This will be useful for you, kindly check and do
Tutorial point site is very easy to learn some important UI basics if you are working in Objective C
My problem is this, in the app when a user clicks somewhere not important an alertView is raised that's ok, I can find the call to that view, but then is showing again and again empty and I have placed breakpoint everywhere I see a call to any alert. But the ghost alert is not breaking anywhere I have no idea who is throwing it is just a sentient view.
Can you give some tips on how to pin point where is the view being called?
EDIT:
Code for the viewController:
#import <CoreLocation/CoreLocation.h>
#import "FormViewController.h"
#import "FormPageViewController.h"
#import "FormElement+UtilityMethods.h"
#import "UserBO.h"
#import "RecordBO.h"
#import "RecordAnswer.h"
#import "UserDefaultsUtilities.h"
#import "TimeTrackingUtilities.h"
#import "DxColors.h"
#import "EDQueueUtilities.h"
#import "GroupAnswerMetadata.h"
#import "RecordAnswer+UtilityMethods.h"
#import "Record+UtilityMethods.h"
#import "FormPageIndexViewController.h"
#import "ManagedObjectUtilities.h"
#import "EDQueue.h"
#import "EDQueueUtilities.h"
#import "DxAnswerObject.h"
#import "ImageAnswerMetadata.h"
#import "DateUtilities.h"
#import <ifaddrs.h>
#import "CarbonKit.h"
#define INITIAL_CONTROLLER_INDEX 0
#define FORM_RECORDS_TEMP_NAME #"<~TMP>"
#define TAG_RETURN_BUTTON 0
#define TAG_SAVE_BUTTON 1
#define TAG_SEND_BUTTON 2
typedef NS_ENUM(NSUInteger, AlertViewPurpose) {
ALERT_VIEW_FORM_NONE = 0,
ALERT_VIEW_FORM_SEND_SUCCESS = 1,
ALERT_VIEW_FORM_SEND_FAILURE = 2,
ALERT_VIEW_FORM_SAVE_PROMPT = 3,
ALERT_VIEW_FORM_FILE_NAME_PROMPT = 4,
ALERT_VIEW_FORM_ASYNC_SEND_SUCCESS = 5,
ALERT_VIEW_FORM_COULDNT_SEND = 6,
ALERT_VIEW_FORM_WANT_TO_SEND = 7,
ALERT_VIEW_FORM_SAVE_IN_CONTEXT_PROMPT = 8,
ALERT_VIEW_FORM_FILE_NAME_IN_CTXT_SAVE_PROMPT = 9,
ALERT_VIEW_FORM_REQUIRED_INTERNET_CONECTION = 10,
// Enumeration counter.
ALERT_VIEW_PURPOSE_COUNT
};
// Based on:
// Ref.: http://www.appcoda.com/uipageviewcontroller-storyboard-tutorial/
#interface FormViewController () <RecordBOProtocol, FieldElementProtocol,
CLLocationManagerDelegate, FormPageIndexProtocol,CarbonTabSwipeNavigationDelegate>
{
AlertViewPurpose _currentAlertViewPurpose;
CarbonTabSwipeNavigation *_carbonTabSwipeNavigation;
BOOL _unedited;
BOOL _formRecordNilAtStartUp;
BOOL _timestampTaken;
CLLocationManager *_locationManager;
CLLocation *_location;
NSDate *_timeSpentBaseTimestamp;
NSArray *_sortedPages;
NSUInteger _currentPageIndex;
NSString *formID;
NSArray *_pagesNames;
}
#property (weak, nonatomic) IBOutlet UILabel *lblFormTitle;
#property (weak, nonatomic) IBOutlet UIButton *btnSmallReturn;
#property (weak, nonatomic) IBOutlet UIButton *btnSmallSave;
#property (weak, nonatomic) IBOutlet UIButton *btnSmallSend;
#property (weak, nonatomic) IBOutlet UIButton *btnBigSend;
#property (weak, nonatomic) IBOutlet UIBarButtonItem *btnReturn;
#property (strong, nonatomic) IBOutlet UIButton *lblBack;
#property (strong, nonatomic) IBOutlet UIButton *lblSave;
#end
#implementation FormViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
_currentAlertViewPurpose = ALERT_VIEW_FORM_NONE;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self localizedButtons];
// Starting up location manager if form requires it.
// Ref.:
// https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManager_Class/index.html#//apple_ref/occ/instm/CLLocationManager/requestAlwaysAuthorization
if ([self.form.geolocationEnabled boolValue]) {
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
if ([CLLocationManager locationServicesEnabled]) {
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
if (status == kCLAuthorizationStatusNotDetermined) {
// Requesting authorization.
if ([CLLocationManager instancesRespondToSelector:#selector(requestWhenInUseAuthorization)]) {
#ifdef DEBUG_MODE
NSAssert(
[[[NSBundle mainBundle] infoDictionary] valueForKey:#"NSLocationWhenInUseUsageDescription"],
#"For iOS 8 and above, your app must have a value for NSLocationWhenInUseUsageDescription in its Info.plist");
#endif // DEBUG_MODE
[_locationManager requestWhenInUseAuthorization];
}
} else if (status == kCLAuthorizationStatusAuthorizedAlways ||
status == kCLAuthorizationStatusAuthorizedWhenInUse) {
_locationManager.distanceFilter = kCLDistanceFilterNone;
_locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
[_locationManager startUpdatingLocation];
}
}
}
self.lblFormTitle.text = self.form.name ;
// Saving whether self.formRecord was nil at beginning.
// Important for time spent tap calculations.
_formRecordNilAtStartUp = self.formRecord == nil;
[self setup];
//Take the time for counting
_timeSpentBaseTimestamp = [NSDate date];
_unedited = YES;
}
-(void)localizedButtons
{
[self.lblBack setTitle:NSLocalizedString(#"Back", #"Regresar") forState:UIControlStateNormal];
[self.lblSave setTitle:NSLocalizedString(#"Save", #"Guardar") forState:UIControlStateNormal];
[self.btnBigSend setTitle:NSLocalizedString(#"Send", #"Enviar") forState:UIControlStateNormal];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
// Overriding from DxBaseViewController.
-(void)refresh
{
}
-(void)setup
{
// Obtaining sorted pages array.
_sortedPages = [[self.form.pages allObjects]
sortedArrayUsingComparator:^NSComparisonResult(Page *obj1, Page * obj2) {
return [obj1.pageNumber compare: obj2.pageNumber];
}];
//Adding toolBar
NSMutableArray *namesPages = [[NSMutableArray alloc]init];
for (Page *page in _sortedPages) {
NSString *namePage = page.name;
[namesPages addObject:namePage];
}
_pagesNames = [namesPages copy] ;
// Creating by default a record in case there's none.
if (self.formRecord == nil) {
self.formRecord = [Record createInContext:self.managedObjectContext];
// Filling in basic record information.
self.formRecord.name = FORM_RECORDS_TEMP_NAME;
self.formRecord.editable = self.form.editableRecords;
self.formRecord.dateLastSaved = self.formRecord.dateCreated = [NSDate date];
self.formRecord.syncStatusId = [NSNumber numberWithInt:SYNC_STATUS_NOT_SYNCED];
self.formRecord.user = [UserBO loggedInUser];
self.formRecord.form = self.form;
self.formRecord.formId = self.form.pkey;
self.formRecord.temporary = [NSNumber numberWithBool:YES];
self.formRecord.isBeingEdited = [NSNumber numberWithBool:YES];
// Committing record information as is. It will be removed if user doesn't
// want to save changes.
if (![Record commitChangesFromContext:self.managedObjectContext]) {
DebugLog(#"Temp form record couldn't be saved! Check!");
}
// Initializing page view controller.
_carbonTabSwipeNavigation =[[CarbonTabSwipeNavigation alloc] initWithItems:_pagesNames
delegate:self];
_carbonTabSwipeNavigation.toolbar.barTintColor = [DxColors colorWithHexRGB:NEW_FORMS_GREEN];
[_carbonTabSwipeNavigation setNormalColor:[UIColor whiteColor]];
[_carbonTabSwipeNavigation setIndicatorColor:[UIColor whiteColor]];
[_carbonTabSwipeNavigation setSelectedColor:[UIColor whiteColor]];
} else {
[self prepareControllerForEdition];
}
[_carbonTabSwipeNavigation insertIntoRootViewController:self];
self.pageViewController = _carbonTabSwipeNavigation.pageViewController;
}
- (UIViewController *)carbonTabSwipeNavigation:(CarbonTabSwipeNavigation *)carbontTabSwipeNavigation
viewControllerAtIndex:(NSUInteger)index {
_currentPageIndex = index;
// Create a new view controller and pass suitable data.
FormPageViewController *formPageViewController = [[FormPageViewController alloc] init];
formPageViewController.pageIndex = index;
formPageViewController.formPage = _sortedPages[index];
formPageViewController.managedObjectContext = self.managedObjectContext;
formPageViewController.formRecord = self.formRecord;
formPageViewController.observer = self;
formPageViewController.view.frame = CGRectMake(0,
0,
self.view.frame.size.width,
self.view.frame.size.height);
return formPageViewController;
}
#pragma mark - Button Actions (IBActions)
-(IBAction)send:(id)sender
{
_timer = [NSTimer scheduledTimerWithTimeInterval:0.001
target:self
selector:#selector(isAlertViewShowing:)
userInfo:nil
repeats:YES];
[self setButtonWithTag:self.btnBigSend.tag toHighlight:NO];
// Disabling button to avoid double submissions.
self.btnBigSend.enabled = NO;
// Show alert.
[self showAreYouReadyToSubmitFormMsg];
}
... can't paste it all
For testing only:
Subclass UIAlertView i.e. #interface MyAlertView : UIAlertView
Then replace all instances of UIAlertView from MyAlertView
i.e. MyAlertView *someAlert = [[MyAlertView alloc] init.......];
Then override
-(void)show {
[super show];
//Your breakpoint here
OR
NSLog([NSThread callStackSymbols]);
}
Check your viewcontroller that has an uialertviewdelegate.
Log your alertview.delegate
Check your super class of a viewcontroller that it doesn't call uialertviewdelegate function.
If it is an UIAlertController, check viewwillappear, viewdidappear, viewwilldisappear (super class too) and find out they don't call [alertview show]
Why you take enum for alertview ? just make instance of UIAlertView where it require's to show. you can make one method in which you can pass two string parameters alertview massage and title and method shows alertview with this title and massage.
You can catch the content of your AlertView, if it has no content at all, don't present it!
To do this check the message you are passing to the method that presents the alertView.
However, I can't seem to find your method showAreYouReadyToSubmitFormMsg.
When presenting a new ViewController using the:
UINavigtionController *nav = [[UINavigationController alloc] initWithRoot(myVC)]
[self presentViewController:nav animated:YES completion:nil];
The UIViewControllerTransitionDelegate is never triggered since I am declaring this in myVC. My question is thus: how do I properly setup a interactive transition using the above initializiation?
EDIT:
I tried to follow the advice given below with no luck yet:
VC1.m :
LTFollowersListViewController *f = [LTFollowersListViewController new];
f.delegate = self;
LTNavigationController *nav = [[LTNavigationController alloc] initWithRootViewController:f];
[self presentViewController:nav animated:YES completion:nil];
VC2.h:
#interface LTFollowersListViewController : UIViewController <UIViewControllerTransitioningDelegate>
#property (nonatomic, strong) id<UIViewControllerTransitioningDelegate> delegate;
VC2.m:
#property (nonatomic, strong) CEPanAnimationController *animationController;
#property (nonatomic, strong) CEHorizontalSwipeInteractionController *interactionController;
in the viewDidLoad: {
self.delegate = self;
self.animationController = [[CEPanAnimationController alloc] init];
self.interactionController = [[CEHorizontalSwipeInteractionController alloc] init];
}
in the bottom of file:
#pragma mark - UIViewControllerTransitionsingDelegate
- (id<UIViewControllerAnimatedTransitioning>)
animationControllerForPresentedController:(UIViewController *)presented
presentingController:(UIViewController *)presenting
sourceController:(UIViewController *)source {
NSLog(#"Reached the animation dismissal");
// allow the interaction controller to wire-up its gesture recognisers
[self.interactionController wireToViewController:self.navigationController forOperation:CEInteractionOperationDismiss];
self.animationController.reverse = NO;
return self.animationController;
}
- (id<UIViewControllerAnimatedTransitioning>)
animationControllerForDismissedController:(UIViewController *)dismissed {
self.animationController.reverse = YES;
return self.animationController;
}
- (id<UIViewControllerInteractiveTransitioning>)
interactionControllerForDismissal:
(id<UIViewControllerAnimatedTransitioning>)animator {
NSLog(#"Reached the animation interaction");
// provide the interaction controller, if an interactive transition is in progress
return self.interactionController.interactionInProgress
? self.interactionController : nil;
}
Any suggestions as to what I am missing here? Thanks!
Did you miss
.h file declare the delegate and protocol ViewController will implement
#interface ViewController : UIViewController<UIViewControllerTransitioningDelegate>
#property (nonatomic, strong) id<UIViewControllerTransitioningDelegate> delegate;
.m file Setting the delegate
self.delegate = self;
and also implement the delegate methods.
I'm adding a subview the following way"
SettingsViewController *SVC = [[SettingsViewController alloc] initWithNibName:#"SettingsViewController" bundle:[NSBundle mainBundle]];
[self.parentViewController addChildViewController:SVC];
[self.view addSubview:SVC.view];
My subview is 300 x 360 and is centered on the screen. The problem occurs when I attempt to remove it (Getting released).
When I press the close button in this new view, I get exc bad access. What's the correct way to add my view? I have a SettingsViewController.xib linked up to a .h and .m file.
Here's what my close button in my settings view looks like:
-(IBAction)close:(id)sender {
[self.view removeFromSuperview];
[self removeFromParentViewController];
}
But even when I comment out everything inside, just triggering the button crashes the app.
This is what my .h file looks like:
#import <UIKit/UIKit.h>
#interface SettingsViewController : UIViewController
#property (nonatomic, strong) IBOutlet UIView *alertView;
#property (nonatomic, strong) IBOutlet UIButton *closeButton;
#property (nonatomic, strong) IBOutlet UILabel *musicLabel;
#property (nonatomic, strong) IBOutlet UILabel *soundFXLabel;
#property (nonatomic, strong) IBOutlet UILabel *vibrateLabel;
- (IBAction)close:(id)sender;
#end
and my implementation file:
#import "SettingsViewController.h"
#interface SettingsViewController ()
#end
#implementation SettingsViewController
#synthesize alertView;
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.alpha = 0;
self.alertView.layer.cornerRadius = 10.0f;
self.alertView.layer.borderColor = [UIColor whiteColor].CGColor;
self.alertView.layer.borderWidth = 4.0f;
self.closeButton.layer.cornerRadius = 5.0f;
self.closeButton.titleLabel.font = [UIFont fontWithName:#"SourceSansPro-Bold" size:20];
self.musicLabel.font = [UIFont fontWithName:#"SourceSansPro-Bold" size:30];
self.soundFXLabel.font = [UIFont fontWithName:#"SourceSansPro-Bold" size:30];
self.vibrateLabel.font = [UIFont fontWithName:#"SourceSansPro-Bold" size:30];
[UIView animateWithDuration:0.3
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
self.view.alpha = 1;
}
completion:^(BOOL finished){
//Display Players View
}];
}
- (IBAction)close:(id)sender {
//[self.view removeFromSuperview];
//[self removeFromParentViewController];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
And last but not least, here's a snapshot of my storyboard / xib order:
create a property for your SettingsViewController where you add & assign it where you create it.
// in .h file or private category on top
#property (nonatomic, strong) SettingsViewController *settingsController;
// your usual code + assigning controller
SettingsViewController *SVC = [[SettingsViewController alloc] initWithNibName:#"SettingsViewController" bundle:[NSBundle mainBundle]];
[self.parentViewController addChildViewController:SVC];
[self.view addSubview:SVC.view];
self.settingsController = SVC;
Side Note : the reason for this behavior is after the .view property of the ViewController is added to your view, the controller gets deallocated (only the .view is alive now). So when you try to hit the butons on view there is no SettingsViewController to callback those events, hence crash. When you create the property & assign it, the controller lives.
The style should be like iBooks or pictures in foursquare. When we flip to the left we see the next picture being pulled. How to do so? Is there a code to do so? I think there must have been a ready code for that
It sounds like you want UIPageViewController.
Try this. One solution. Revise as needed.
Create a new project of type Single View Application, name it BookEffect, uncheck Use Storyboards, uncheck Include Unit Tests, but be sure to check the option Use Automatic Reference Counting.
Then add to the project a few pictures, for example, in JPEG format.
Create a new file - use the Objective-C Class template with a subclass of UIViewController, select the option With XIB for user interface, and name it SinglePageViewController. Save the file inside the BookEffect folder.
Once added, select the SinglePageViewController.xib and add to the view a UILabel control and UIImageView control and make the appropriate connections to the File's Owner.
Revise the SinglePageViewController.h to look like this:
#import <UIKit/UIKit.h>
#interface SinglePageViewController : UIViewController
{
NSUInteger pageNumber;
}
#property (strong, nonatomic) IBOutlet UILabel *titleLabel;
#property (strong, nonatomic) IBOutlet UIImageView *imageView;
#property (nonatomic, assign) NSUInteger pageNumber;
- (void) setPageNumber: (NSUInteger) newPageNumber;
- (NSUInteger) pageNumber;
#end
In SinglePageViewController.m add:
#synthesize imageView, titleLabel;
and add these definitions of methods:
- (void) setPageNumber: (NSUInteger) newPageNumber{
pageNumber = newPageNumber;
}
- (NSUInteger) pageNumber{
return pageNumber;
}
- (void) viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[titleLabel setText:[NSString stringWithFormat:#"Page %d", pageNumber]];
NSArray *images = [[NSBundle mainBundle] pathsForResourcesOfType:#".jpg" inDirectory:nil];
UIImage *img = [UIImage imageWithContentsOfFile:[images objectAtIndex:pageNumber-1]];
[imageView setImage:img];
}
Now go to the BookEffecViewController.h, and make it look like this:
#import <UIKit/UIKit.h>
#import "SinglePageViewController.h"
#interface BookEffectViewController : UIViewController
<UIPageViewControllerDataSource>
#property( nonatomic, strong) UIPageViewController *pageViewController;
#end
In BookEffectViewController.m revise viewDidLoad to look like this:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.pageViewController.dataSource = self;
SinglePageViewController *singlePage = [[SinglePageViewController alloc] initWithNibName:#"SinglePageViewController" bundle:nil];
[singlePage setPageNumber:1];
NSArray *controllers = [[NSArray alloc] initWithObjects:singlePage, nil];
[self.pageViewController setViewControllers:controllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
self.pageViewController.view.frame = self.view.bounds;
}
Define two more methods in BookEffectViewController.m:
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger previousPageNumber = [((SinglePageViewController*)viewController) pageNumber];
if ( previousPageNumber == 1 ) {
return nil;
}
else{
SinglePageViewController *singlePage = [[SinglePageViewController alloc] initWithNibName:#"SinglePageViewController" bundle:nil];
[singlePage setPageNumber:previousPageNumber-1];
return singlePage;
}
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger previousPageNumber = [((SinglePageViewController*)viewController) pageNumber];
if ( previousPageNumber >= [[[NSBundle mainBundle] pathsForResourcesOfType:#".jpg" inDirectory:nil] count] ) {
return nil;
}
else{
SinglePageViewController *singlePage = [[SinglePageViewController alloc] initWithNibName:#"SinglePageViewController" bundle:nil];
[singlePage setPageNumber:previousPageNumber+1];
return singlePage;
}
}
That's it. Command-R to test it with the iPad Simulator
This is a basic shell and other bells and whistles can be added for your own pleasure, i.e. take out Page Number, add a caption, etc.
Hope this helped.