I'm a newbie on coding in objective-c.
I'm currently making an exercise application where I need to get some json-data from an API with a NSURLSession and send the date to a PageViewController.
So currently I'm getting my json-data in the method 'getWeer',which I call before making the pageViewController (in viewDidLoad). But because the NSURLSession runs async I think and isn't complete, the json-data always is null when I try to access it in my pageViewController.
How can I make the pageViewController after the NSURLSession is complete?
#interface SecondViewController ()<CLLocationManagerDelegate>
#property (nonatomic, strong) CLLocationManager *locationManager;
#property (nonatomic, strong) NSString *AppId;
#property (nonatomic, weak) NSDictionary *json;
#end
#implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.AppId = #"feda1f13263bb730deeb89fb3936a76e";
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[[self locationManager] requestWhenInUseAuthorization];
[[self locationManager] startUpdatingLocation];
[self getWeer];
// Create page view controller
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageViewController"];
self.pageViewController.dataSource = self;
PageContentViewController *startingViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = #[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
// Change the size of page view controller
self.pageViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 30);
[self addChildViewController:_pageViewController];
[self.view addSubview:_pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (PageContentViewController *)viewControllerAtIndex:(NSUInteger)index{
// Create a new view controller and pass suitable data.
PageContentViewController *pageContentViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageContentViewController"];
pageContentViewController.pageIndex = index;
NSLog(#"%#",self.json);
pageContentViewController.json = self.json;
return pageContentViewController;
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController{
NSUInteger index = ((PageContentViewController*) viewController).pageIndex;
if ((index == 0) || (index == NSNotFound)) {
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController{
NSUInteger index = ((PageContentViewController*) viewController).pageIndex;
if (index == NSNotFound) {
return nil;
}
index++;
if (index == 3) {
return nil;
}
return [self viewControllerAtIndex:index];
}
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController{
return 3;
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController{
return 0;
}
-(void)getWeer{
NSString *dataUrl = [NSString stringWithFormat:#"http://api.openweathermap.org/data/2.5/forecast/daily?lat=%f&lon=%f&cnt=4&&APPID=%#&units=metric&lang=nl", self.locationManager.location.coordinate.latitude, self.locationManager.location.coordinate.longitude, self.AppId];
NSLog(#"%f",self.locationManager.location.coordinate.latitude);
NSLog(#"%f",self.locationManager.location.coordinate.longitude);
NSURL *url = [NSURL URLWithString:dataUrl];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
self.json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
});
}];
[dataTask resume];
}
#end
Call this method after async finish.
// Create page view controller
-(void)setupPageViewController {
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageViewController"];
self.pageViewController.dataSource = self;
PageContentViewController *startingViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = #[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
// Change the size of page view controller
self.pageViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 30);
[self addChildViewController:_pageViewController];
[self.view addSubview:_pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
}
Related
I have a viewController1 setting a timer.
When the timer countdown to 0, I'll present viewController2.
The timer also keeps going, although I call the timer function invalidate
Then I mark present viewcontroller code, it seems stop correctly.
//ViewController2 *vc = [[ViewController2 alloc] init];
//[self presentViewController:vc animated:false completion:nil];
What's wrong with code?
#import "ViewController.h"
#import <WebKit/WebKit.h>
#import "ViewController2.h"
#interface ViewController ()<WKScriptMessageHandler, WKNavigationDelegate,WKUIDelegate>
#property (nonatomic,strong) WKWebView* webView;
#property (nonatomic, strong) WKWebViewConfiguration * webConfig;
#property (nonatomic, strong) NSTimer *timer;
#property (nonatomic) int count;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:[self createWKWebApp]];
[self.view addSubview: self.webView];
[self.webView.configuration.preferences setValue:#YES forKey:#"allowFileAccessFromFileURLs"];
self.webView.scrollView.bounces = NO;
[self.webView setContentMode:UIViewContentModeScaleAspectFit];
self.webView.navigationDelegate = self;
self.webView.UIDelegate = self;
NSURL *url = [NSURL URLWithString:#"https://www.google.com.tw"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
self.count = 5;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timerFired) userInfo:nil repeats:YES];
}
-(void)timerFired {
NSLog(#"===) self.count : %d", self.count);
if (self.count == 0) {
ViewController2 *vc = [[ViewController2 alloc] init];
[self presentViewController:vc animated:false completion:^{
[self.timer invalidate];
self.timer = nil;
}];
} else {
self.count -= 1;
}
}
- (WKWebViewConfiguration *)createWKWebApp {
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
WKUserContentController *userContent = [[WKUserContentController alloc] init];
config.userContentController = userContent;
return config;
}
- (void)userContentController:(WKUserContentController*)userContentController didReceiveScriptMessage:(WKScriptMessage*)message {
}
#end
Before present a ViewController, stop the timer
[self.timer invalidate];
self.timer = nil;
ViewController2 *vc = [[ViewController2 alloc] init];
[self presentViewController:vc animated:false completion:nil];
Invalidate the timer in viewWillDisappear delegate method and tigger again whenever view will appear again.
I'm building a App to play 360 videos - all is working great !
However, I would like like the video to start to play only if the mobile is oriented in Landscape ! IF in portrait it should display a message "Please put your mobile in landscape" and if so - start to play the video . ..
Anybody have any idea how to achieve this ?
It would be amazing :)
Thanks !
EDIT:
my Viewcontroller.m
//
// ViewController.m
// video360test
//
// Created by linyize on 16/6/20.
// Copyright © 2016年 islate. All rights reserved.
//
#import "ViewController.h"
#import "Video360ViewController.h"
#import "CardboardViewController.h"
#import "CardboardSDK.h"
#implementation ViewController
- (BOOL)prefersStatusBarHidden {
return YES;
}
- (BOOL)shouldAutorotate
{
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (IBAction)playURL:(id)sender
{
NSURL *url = [NSURL URLWithString:#"http://7b1gcw.com1.z0.glb.clouddn.com/demo1.mp4"];
Video360ViewController *videoController = [[Video360ViewController alloc] initWithNibName:#"HTY360PlayerVC" bundle:nil url:url];
if (![[self presentedViewController] isBeingDismissed]) {
[self presentViewController:videoController animated:YES completion:nil ];
}
}
- (IBAction)playFileffpvr:(id)sender
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"demo1" ofType:#"mp4"];
NSURL *url = [NSURL fileURLWithPath:path];
Video360ViewController *videoController = [[Video360ViewController alloc] initWithNibName:#"HTY360PlayerVC" bundle:nil url:url];
[videoController VRMode:true];
if (![[self presentedViewController] isBeingDismissed]) {
[self presentViewController:videoController animated:YES completion:nil];
}
}
- (IBAction)playFileff360:(id)sender
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"demo1" ofType:#"mp4"];
NSURL *url = [NSURL fileURLWithPath:path];
Video360ViewController *videoController = [[Video360ViewController alloc] initWithNibName:#"HTY360PlayerVC" bundle:nil url:url];
if (![[self presentedViewController] isBeingDismissed]) {
[self presentViewController:videoController animated:YES completion:nil];
}
}
- (IBAction)playFile2:(id)sender
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"boa" ofType:#"mp4"];
NSURL *url = [NSURL fileURLWithPath:path];
Video360ViewController *videoController = [[Video360ViewController alloc] initWithNibName:#"HTY360PlayerVC" bundle:nil url:url];
if (![[self presentedViewController] isBeingDismissed]) {
[self presentViewController:videoController animated:YES completion:nil];
}
}
- (IBAction)playFileffp:(id)sender
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"boa" ofType:#"mp4"];
NSURL *url = [NSURL fileURLWithPath:path];
Video360ViewController *videoController = [[Video360ViewController alloc] initWithNibName:#"HTY360PlayerVC" bundle:nil url:url];
if (![[self presentedViewController] isBeingDismissed]) {
[self presentViewController:videoController animated:YES completion:nil];
}
}
#end
#implementation LandscapeNavController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.navigationBarHidden=YES;
}
-(BOOL)shouldAutorotate{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscape;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
EDIT 2:
the button displaying correctly the alert now:
- (IBAction)playFileffpvr:(id)sender
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"demo1" ofType:#"mp4"];
NSURL *url = [NSURL fileURLWithPath:path];
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIDeviceOrientationPortrait)
[self doSomething];
else
[self doSomethingElse];
Video360ViewController *videoController = [[Video360ViewController alloc] initWithNibName:#"HTY360PlayerVC" bundle:nil url:url];
[videoController VRMode:true];
if (![[self presentedViewController] isBeingDismissed]) {
[self presentViewController:videoController animated:YES completion:nil];
}
}
and the alert being display:
-(void)doSomething
{
//Show Alert
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:#"Simple" message:#"Turn your device to Landscape." preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) {
NSLog(#"Cancel");
}];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
NSLog(#"OK");
}];
[alertController addAction:cancelAction];
[alertController addAction:okAction];
[self presentViewController:alertController animated: YES completion: nil];
}
-(void)doSomethingElse
{
//Function Body
//play the file
}
Yes, all you need to do is create an UINavigationController subclass say LandscapeNavController and put the code below
LandscapeNavController.h
#import <UIKit/UIKit.h>
#interface LandscapeNavController : UINavigationController
#end
LandscapeNavController.m
#implementation LandscapeNavController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.navigationBarHidden=YES;
}
-(BOOL)shouldAutorotate{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscape;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
Now present the video controller as modal like mentioned below
VideoController *controller=<INITIALIZE>
LandscapeNavController *nav=[[LandscapeNavController alloc] initWithRootViewController:controller];
[self presentViewController:nav animated:YES completion:nil];
and make sure your rotation settings should be
Additionally in AppDelegate.h define
#property(assign) BOOL shouldRotate;
The above property should be set to YES before you present VideoController and NO before dismissing the VideoController.
And add the following code in AppDelegate.m
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if (shouldRotate)
return UIInterfaceOrientationMaskAll;
else
return UIInterfaceOrientationMaskPortrait;
}
Note - The above code not tested right now, if you face problem ping.
Cheers.
Declare a property for UIAlertController as:
#property (strong, nonatomic)UIAlertController *alertController;
You can Use a code like this:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(deviceOrientationDidChange) name:UIDeviceOrientationDidChangeNotification object:nil];
}
-(void)deviceOrientationDidChange
{
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIDeviceOrientationPortrait)
[self doSomething];
else
[self doSomethingElse];
}
-(void)doSomething
{
//Show Alert
self.alertController = [UIAlertController alertControllerWithTitle:#"Simple" message:#"Turn your device to Landscape." preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) {
NSLog(#"Cancel");
}];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
NSLog(#"OK");
}];
[self.alertController addAction:cancelAction];
[self.alertController addAction:okAction];
[self presentViewController:alertController animated: YES completion: nil];
}
-(void)doSomethingElse
{
//Hide the AlertViewController
[self.alertController removeFromSuperview];
//Code to handle the playing of the file
}
-(BOOL)shouldAutorotate{
return YES;
}
Happy Coding. Hope it helps.
So I present an EKEventViewController with a UINavigationController. From inside the EKEventViewController I am able to edit the event. It presents an EKEventEditViewController. Everything thing works great(cancel/done buttons) except when I delete the event inside the EKEventEditViewController I recieve this
attempt to dismiss modal view controller whose view does not currently appear. self = modalViewController =
Here is my code...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[CalendarViewController connectExchange];
if (connectionEx == YES)
{
NSDate *dateRepresentingThisDay = [self.sortedDays objectAtIndex:indexPath.section];
NSArray *eventsOnThisDay = [self.sections objectForKey:dateRepresentingThisDay];
EKEventViewController *eventViewController = [[EKEventViewController alloc] init];
eventViewController.allowsEditing = YES;
eventViewController.delegate = self;
EKEvent *event = [eventsOnThisDay objectAtIndex:indexPath.row];
eventViewController.event = event;
UINavigationController *navBar = [[UINavigationController alloc]initWithRootViewController:eventViewController];
[self.navigationController presentViewController:navBar animated:YES completion:nil];
}
}
- (void)eventViewController:(EKEventViewController *)controller didCompleteWithAction:(EKEventViewAction)action
{
EKEvent *event = controller.event;
CalendarViewController * __weak weakSelf = self;
// Dismiss the modal view controller
[self dismissViewControllerAnimated:YES completion:^
{
if (action == EKEventViewActionDone)
{
dispatch_async(dispatch_get_main_queue(), ^{
NSError *err;
[self.eventStore saveEvent:event span:EKSpanThisEvent error:&err];
[self updateEvent:event];
});
}
if (action == EKEventViewActionDeleted)
{
dispatch_async(dispatch_get_main_queue(), ^{
[self deleteEvent:event];
NSError *error;
EKEvent *eventRemove = [self.eventStore eventWithIdentifier:event.eventIdentifier];
[self.eventStore removeEvent:eventRemove span:EKSpanThisEvent error:&error];
});
}
if (action == EKEventViewActionResponded)
{
dispatch_async(dispatch_get_main_queue(), ^{
});
}
weakSelf.eventsList = [self fetchEvents];
[weakSelf.tableView reloadData];
NSLog(#"Event Updated");
}];
}
How am I suppose to properly dismiss the ViewControllers after deleting the event via the EKEventEditViewController?
I solved my problem by subclassing EKEventViewController and setting up EKEventEditViewDelegate and EKEventViewDelegate.
Here is my changed didSelectRow(CalendarViewController.m),
EditViewController *eventViewController = [[EditViewController alloc] init];
eventViewController.allowsEditing = YES;
eventViewController.delegate = self;
EKEvent *event = [eventsOnThisDay objectAtIndex:indexPath.row];
eventViewController.event = event;
[self.navigationController pushViewController:eventViewController animated:YES];
self.editingEvent = eventViewController.event;
The EditViewController is my subclass of EKEventViewController.
In the subclass(EditViewController.m) I added my own edit button with a selector in viewDidLoad,
- (void)viewDidLoad
{
[super viewDidLoad];
UIBarButtonItem *editItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self.delegate action:#selector(editCalEvent)];
self.navigationItem.rightBarButtonItem = editItem;
}
Now back in CalendarViewController.m after adding the EKEventEditViewDelegate and EKEventViewDelegate to the #interface I added new methods
- (void)editCalEvent
{
EKEventEditViewController *editController = [[EKEventEditViewController alloc] init];
editController.event = self.editingEvent;
editController.eventStore = self.eventStore;
editController.editViewDelegate = self;
[self presentViewController:editController animated:YES completion:nil];
}
- (void)eventEditViewController:(EKEventEditViewController *)controller didCompleteWithAction (EKEventEditViewAction)action
{
EKEvent *thisEvent = controller.event;
[self dismissViewControllerAnimated:NO completion:^
{
switch (action)
{
{case EKEventEditViewActionCanceled:
//NSLog(#"Canceled action");
break;}
{case EKEventEditViewActionSaved:
[self.eventStore saveEvent:thisEvent span:EKSpanThisEvent error:nil];
[self updateEvent:thisEvent];
break;}
{case EKEventEditViewActionDeleted:
[self deleteEvent:thisEvent];
NSError *error;
EKEvent *eventRemove = [self.eventStore eventWithIdentifier:thisEvent.eventIdentifier];
[self.eventStore removeEvent:eventRemove span:EKSpanThisEvent error:&error];
//NSLog(#"Deleted action");
break;}
{default:
break;}
}
}];
}
- (void)eventViewController:(EKEventViewController *)controller didCompleteWithAction:(EKEventViewAction)action
{
}
Use the editViewDelegate instead of delegate.
I currently have a UIPageViewController set up in my project almost exactly like the default page-based application template.
However, in the init method for my ModelController I am using NSURLConnection to async download data into an array (of images) that is supposed to be displayed on the PageViewController.
That means when my root view controller goes and inits a starting view controller the resources might not be downloaded yet and then the model controller is fetching things from an empty array which crashes the app.
How can I implement a safe way to show the images in a PageView? I was thinking of using an empty view controller with an activity indicator as the starting view controller but I don't know how I'd then let the model controller know when the download is completed so I can then update the views with the images.
my root view controller (this is the uipageviewcontroller delegate)
#interface CSAPromoViewController ()
#property (readonly, strong, nonatomic) CSAPromoModelController *modelController;
#end
#implementation CSAPromoViewController
#synthesize modelController = _modelController;
- (void)viewDidLoad
{
[super viewDidLoad];
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.pageViewController.delegate = self;
CSAPageDataViewController *startingViewController = [self.modelController viewControllerAtIndex:0 storyboard:self.storyboard];
NSArray *viewControllers = #[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
self.pageViewController.dataSource = self.modelController;
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
//set page view controller's bounds
CGRect pageViewRect = self.view.bounds;
self.pageViewController.view.frame = pageViewRect;
[self.pageViewController didMoveToParentViewController:self];
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
}
my model controller (this is the data source)
#interface CSAPromoModelController()
#property (readonly, strong, nonatomic) NSArray *promosArray;
#end
#implementation CSAPromoModelController
-(id)init
{
self = [super init];
if (self) {
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://blah.com"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
_promosArray = [self parseJSON:data];
}];
}
return self;
}
- (CSAPageDataViewController *)viewControllerAtIndex:(NSUInteger)index storyboard:(UIStoryboard *)storyboard
{
// Return the data view controller for the given index.
if (([self.promosArray count] == 0) || (index >= [self.promosArray count] / 2)) {
return nil;
}
// Create a new view controller and pass suitable data.
CSAPageDataViewController *dataViewController = [storyboard instantiateViewControllerWithIdentifier:#"CSAPageDataViewController"];
dataViewController.promoOne = [self.promosArray objectAtIndex:index * 2];
dataViewController.promoTwo = [self.promosArray objectAtIndex:(index * 2) + 1];
return dataViewController;
}
the data view controller
#implementation CSAPageDataViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.promoLabelTop.text = [self.promoOne name];
self.promoImageTop.image = [self.promoOne image];
self.promoLabelBottom.text = [self.promoTwo name];
self.promoImageBottom.image = [self.promoTwo image];
}
Your problem you're trying to solve is an asynchronous one. Your approach however is for solving a synchronous problem.
For example, your class CSAPromoModelController is inherently asynchronous. This is because it's init method invokes an asynchronous method, and thus your class gets "infected" by asynchronism.
You might consider a re-design, where class CSAPromoModelController becomes a subclass of NSOperation with a complete handler, e.g. CSAPromoModelOperation. It's eventual result is the array of images. The imageArray becomes an ivar of your CSAPromoViewController. The CSAPromoViewController will have a method for creating a CSAPromoModelController object which will be initialized with an image. The completion handler of the operation passes the array of images. Within the completion handler you basically execute the same statements as in your original viewDidLoad method in order to setup the controllers.
You would use the operation as follows:
- (void)viewDidLoad
{
[super viewDidLoad];
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.pageViewController.delegate = self;
NSURLRequest *request = ...
CSAPromoModelOperation* op =
[CSAPromoModelOperation alloc] initWithRequest:request
completion:^(NSArray* result, NSError*error)
{
// assuming we are executing on the main thread!
if (error == nil) {
self.imageArray = result;
CSAPageDataViewController* startingViewController =
[self viewControllerWithImage:self.imageArray[0]
storyboard:self.storyboard];
NSArray* viewControllers = #[startingViewController];
[self.pageViewController setViewControllers:viewControllers
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
...
}
else {
// handle error
}
}];
[op start];
}
This is my first post because I usually find all the answers on stack overflow but not this time !
I have a little problem.
I am using the following methods :
-(void)scrollToTop;
{
[_scrollView setContentOffset:CGPointZero animated:YES];
}
sometimes it animates sometimes not !
This one works :
-(void)newPage:(NSString*)href
{
if(!(_pageNumber == href.integerValue))
{
__weak id weakSelf = self;
[(PageViewController*)_preLoadPages[href] setPageMinHeight:_actualPage.height];
NSMutableArray *viewControllers = [[NSMutableArray alloc] init];
viewControllers[0] = _preLoadPages[href];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:^(BOOL finished){
[weakSelf afterLinkClicked:href];
}];
_pageNumber = href.integerValue;
}
}
- (void)afterLinkClicked:(NSString*)href
{
_pageNumber = href.integerValue;
[_preLoadPages[href] setPageMinHeight:0];
_actualPage = _preLoadPages[href];
[_preLoadPages removeAllObjects];
[self updateScrollView];
[self scrollToTop];
[self parsePage];
}
Whereas this one does not :
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
CGPoint test = [gestureRecognizer locationInView:gestureRecognizer.view];
if(test.x>=742)
{
if(_preLoadPages[#"next"]!=nil)
{
__weak id weakSelf = self;
[(PageViewController*)_preLoadPages[#"next"] setPageMinHeight:_actualPage.height];
NSMutableArray *viewControllers = [[NSMutableArray alloc] init];
viewControllers[0] = _preLoadPages[#"next"];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:^(BOOL finished){
[weakSelf afterAnimationCompleted];
}];
}
}
return YES;
}
- (void)afterAnimationCompleted
{
_pageNumber++;
[_preLoadPages[#"next"] setPageMinHeight:0];
_actualPage = _preLoadPages[#"next"];
[_preLoadPages removeAllObjects];
[self updateScrollView];
[self scrollToTop];
[self parsePage];
}
There is practically no differences between these two calls !
I have tried to use performSelector: withObject: withDelay:0 but it doesn't work too !!