ios pushing to navigationController ends in black screen - ios

I tried to implement stripe into an iOS app through its online documentation. Everything good so far, now pushing the paymentView onto my navigation controller stack I get a completely broken screen. Thought it'd be a problem with the stripe view but when I do not log in (see code below - no identification token given) and the login screen is being pushed instead, it is completely black too. It cant be a problem with that view cause it loads just fine if I push the login view from another view before this one.
So why does pushing view via the buyButtonAction below give me black / fucked up screens?!
Ive been on this for hours.. nothing seems to work.
A pic:
the important code part:
#interface PaymentViewController ()
#end
#implementation PaymentViewController
#synthesize stripeCard = _stripeCard;
#synthesize stripeView;
#synthesize passedProductId;
- (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.stripeView = [[STPView alloc] initWithFrame:CGRectMake(15,20,290,55)
andKey:#"pk_test_45mqixOu8N9S4lQ6cdn1OXBD"];
self.stripeView.delegate = self;
[self.view addSubview:self.stripeView];
}
And the call:
-(void)buyButtonAction:(id)sender
{
tokenClass *tokenObject = [tokenClass getInstance];
NSLog(#"%#", tokenObject.token);
if (tokenObject.token == nil) {
LoginController *loginController = [[LoginController alloc] init];
[self.navigationController pushViewController:loginController animated:YES];
} else {
NSLog(#"%#", tokenObject.token);
CGPoint hitPoint = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *hitIndex = [self.tableView indexPathForRowAtPoint:hitPoint];
PaymentViewController *payView = [[PaymentViewController alloc] init];
payView.passedProductId = [[self.productData valueForKey:#"id"] objectAtIndex:hitIndex.row];
NSLog(#"passing %#", payView.passedProductId);
// push payment view
payView.navigationItem.title = #"One-Click-Payment";
[self.navigationController pushViewController:payView animated:YES];
}
}

We can see that there's a view behind the navigation bar. It's an iOS 7 related issue. Add this line to your viewDidLoad:
if ([self respondsToSelector:#selector(edgesForExtendedLayout)])
self.edgesForExtendedLayout = UIRectEdgeNone;
Or change your self.stripeView frame by adding 64 to y:
CGRectMake(15,84,290,55)
Useful link: https://stackoverflow.com/a/18103727/1835155

Related

Can't see view controller content after pushing to table view controller

I'm new i iOS and Objective-C world, I want to create an example app to learn something but i find some problems in my program.
I Create a TableViewController with Books names, and after touch a book I want see a some more inforamtion about this book.
So I created book class what is a view controller, i created a some Labels inside this class with some text.
NSLogs works fine. After touch the record, apps pushing to new view controller from table view controller worsk good, but I can't see any content over there instead of white bg and back button at the top.
this is book class:
#import "BooksViewController.h"
#interface BooksViewController ()
#end
#implementation BooksViewController
- (id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
if(self){
self.title = self.bookName;
self.view.backgroundColor = [UIColor whiteColor];
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
UILabel *bookNameLabel = [[UILabel alloc] init];
bookNameLabel.text = self.bookName;
bookNameLabel.frame = CGRectMake(10, 10, 300, 50);
[self.view addSubview:bookNameLabel];
UILabel *authorNameLabel = [[UILabel alloc] init];
authorNameLabel.text = self.authorName;
authorNameLabel.frame = CGRectMake(50, 50, 300, 40);
[self.view addSubview:authorNameLabel];
UILabel *bookDescLabel = [[UILabel alloc] init];
bookDescLabel.text = self.bookDesc;
bookDescLabel.frame = CGRectMake(50, 50, 300, 40);
[self.view addSubview:bookDescLabel];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
this is a methods in table view controller witch I use to create a books inforamtion window:
- (void)viewDidLoad {
[super viewDidLoad];
self.bookNames = #[#"Pan Tadeusz", #"Potop", #"Lalka", #"Uczta dla wron", #"Symfonnia C++"];
self.authorsName = #[#"Adam Mickiewicz", #"Henryk Sienkiewicz", #"Bolesław Prus", #"George R.R Martin", #"Jerzy Greborz"];
self.bookDescs = #[#"Opis Pan Tadeusz", #"Opis Potop", #"Opis Lalka", #"Opis Uczta dla wron", #"Opis Symfonnia C++"];
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Książka na pozycji %ld tapped",indexPath.row);
BooksViewController *bookVC = [[BooksViewController alloc] init];
bookVC.bookName = self.bookNames[indexPath.row];
bookVC.authorName = self.authorsName[indexPath.row];
bookVC.bookDesc = self.bookDescs[indexPath.row];
NSLog(#"Nazwa wybranej książki: %#",bookVC.bookName);
[self.navigationController pushViewController:bookVC animated:YES];
}
You're doing this wrong.
First, create an iVar that will save the Indexpath that the user selected, for that, simply add an NSIndexPath variable at the very top of your .m file.
#implementation yourControllerNameHere (){ //In your code you will have your controller name, just add the NSIndexpath ;)
NSIndexPath *selectedPath;
}
You then need to perform a segue when you select a tableview cell, for that, replace your -didSelectRowAtIndexPath method with this :
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Książka na pozycji %ld tapped",indexPath.row);
selectedPath = indexPath; //We're saving the selected path to our instance variable ! This is very important otherwise we can't find it again.
[self performSegueWithIdentifier:#"fromBooksToDetail"];
}
and add the -prepareForSegue method in your .m file ; it should be there when you first created it ! just find it and add the following
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:#"fromBooksToDetail"]){
BooksViewController *bookVC =(BooksViewController*)segue.destinationViewController;
bookVC.bookName = self.bookNames[selectedPath.row];
bookVC.authorName = self.authorsName[selectedPath.row];
bookVC.bookDesc = self.bookDescs[selectedPath.row];
NSLog(#"Nazwa wybranej książki: %#",bookVC.bookName);
}
}
Now this will NOT work unless you add a segue link between your two viewcontrollers in storyboard, so simply open your storyboard and, using a right clic or a ctrl+left clic, drag your mouse from your TableViewController to your BooksController. Don't forget to give it the right identifier in the Attributes Inspector on the right panel !
Note that I wouldn't have named them like that ; BooksViewController has more sense if it's the TableViewController name, and "BookDetailViewController" for the detail page. But that's just a detail.
Once you have the segue link, the performSegue call and the prepareForSegue method, you'll be all set ;)
You need to learn how to debug. Try putting NSLog(#"bookname: %#", self.bookName) in your viewDidLoad and see if you print anything. (Most probably not)
I'm not 100% sure how the view life cycle works when you use alloc init for a view controller. But my bet is that the properties are not set there. Try moving bookNameLabel.text = self.bookName; to viewWillAppear instead of viewDidLoad
You should use storyboards instead. It's super easy.
Also, your initWithNibName will never get called. You are using the init-method.

Memory warning doesn't work properly

I'm practicing on how TabViewcontroller works. Now I have 2 subclasses of UIViewcontroller.
One is HypnosisViewController , the other is TimeViewController.
What I wanted to check is how -(void)viewDidLoad works when IOS simulator gets memory warning.
And I did
Built and ran the app
The console said "HypnosisViewcontroller loaded its view."
Switched the other tab (TimeViewController)
Saw the message in the console. It says "TabViewcontroller loaded its view"
Did the simulator memory warning command in IOS simulator
The console said "HypnoTime Received memory warning."
Switched back to the HypnosisViewcontroller to see whether the console says "HypnosisViewcontroller loaded its view." again.
So the problem here is HypnosisViewcontroller is not destroyed and created again. (Because I can't see the log message when I switch back to HypnosisViewcontroller.)However I leaned the view not on the screen should be destroyed during the memory warning.
Did I miss something? Thanks in advance!
HypnosisViewController.m:
#import "HypnosisViewController.h"
#import "HypnosisView.h"
#implementation HypnosisViewController
-(void)loadView
{
//Create a view
CGRect frame = [[UIScreen mainScreen] bounds];
HypnosisView *v = [[HypnosisView alloc] initWithFrame:frame];
// Set it as *the* view of this view controller
[self setView:v];
}
-(id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle
{
self = [super initWithNibName:nil
bundle:nil];
if(self){
//Get the tab bar item
UITabBarItem *tbi = [self tabBarItem];
//Give it a label
[tbi setTitle:#"Hypnosis"];
//Create a UIImage from a file
//This will use Hypno#2x.png on retina display devices
UIImage *i = [UIImage imageNamed:#"Hypno.png"];
// Put that image on the tab bar item
[tbi setImage:i];
}
return self;
}
-(void)viewDidLoad
{
// Always call the super implmetaion of viewDidload
[super viewDidLoad];
NSLog(#"HypnosisViewcontroller loaded its view");
}
#end
TimeViewController.m:
#import "TimeViewController.h"
#implementation TimeViewController
-(IBAction)showCurrentTime:(id)sender
{
NSDate *now = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setTimeStyle:NSDateFormatterMediumStyle];
[timeLabel setText:[formatter stringFromDate:now]];
[timeLabel2 setText:[formatter stringFromDate:now]];
}
-(id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle
{
// Call the superclass's designated initializer
self = [super initWithNibName:nil
bundle:nil];
//Get a pointer to the application bundle object
// NSBundle *appBundle = [NSBundle mainBundle];
// self = [super initWithNibName:#"TimeViewController"
//bundle:appBundle];
if(self){
//Get the tab bar item
UITabBarItem *tbi = [self tabBarItem];
//Give it a label
[tbi setTitle:#"Time"];
//Create a UIImage from a file
//This will use Time#2x.png on retina display devices
UIImage *i = [UIImage imageNamed:#"Time.png"];
// Put that image on the tab bar item
[tbi setImage:i];
}
return self;
}
-(void)viewDidLoad
{
// Always call the super implmetaion of viewDidload
[super viewDidLoad];
NSLog(#"TimeViewcontroller loaded its view");
// [[self view] setBackgroundColor:[UIColor greenColor]];
}
#end
Memory Warnings don't cause the Controllers to destroy/unload their views anymore.
It is working properly. And HypnosisViewcontroller was destroyed and created again, because viewDidLoad will be called only when all the views are initiated. So here you see the log message again when you switch back to HypnosisViewcontroller which represent that HypnosisViewcontroller has been purged from memory and initiated again. You can try switch between these two view controllers without simulating memory warning, and you will only see the log message once.

iOS Orientation issue from landscape to portrait

I've lost enough sleep trying to figure this one out. I have a tabbed application that supports all orientations. Everything works completely fine when the app starts in portrait and switches to landscape. When the app starts in landscape however and then switches to portrait, I lose response ONLY on the bottom quarter of the screen! It's as if something in the background is not adjusting the "user interaction" area from landscape bounds to portrait bounds when the orientation changes.
I have two tabs at the moment. When I switch to the second tab, and then back to the first, the problem goes away! I'm able to interact with the bottom quarter of the screen again. I've gotten that similar problem before when I setup the tab view controller away in viewDidLoad as opposed to viewDidAppear. Everything is in viewDidAppear now.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidAppear:(BOOL)animated
{
NSArray* controllers = nil;
TimeTableViewController * timeTableViewController = [[TimeTableViewController alloc] init];
FRLayeredNavigationController *timeTableNavController = [[FRLayeredNavigationController alloc] initWithRootViewController:timeTableViewController configuration:^(FRLayeredNavigationItem *item)
{
item.hasChrome = YES;
}];
timeTableNavController.dropLayersWhenPulledRight = true;
TestViewController* vc2 = [[TestViewController alloc] init];
timeTableNavController.tabBarItem = [[UITabBarItem alloc]
initWithTitle:#"Student Lookup"
image:[UIImage imageNamed:#"search_gray.png"]
tag:0];
timeTableNavController.tabBarItem = [[UITabBarItem alloc]
initWithTitle:NSLocalizedString(#"Attendance", #"Attendance")
image:[UIImage imageNamed:#"attendance_gray.png"]
tag:0];
timeTableNavController.view.backgroundColor = [UIColor lightGrayColor];
controllers = [NSArray arrayWithObjects:timeTableNavController,vc2, nil];
self.viewControllers = controllers;
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
I don't think the FRLayeredNavigationController library is an issue. Is there any method I can call that readjusts the "area of response" when switching from landscape to portrait? That would be a life-saver. Someone please beat some sense into me!
In fact when you start your app in landscape mode, it should starts in portrait and then your viewcontroller need to rotate this.
In fact you have 3 approaches:
First and i think the best:
https://stackoverflow.com/a/10533561/2204866
Or you can create separates views with separate xib's for each
mode.
Easiest way to support multiple orientations? How do I load a custom NIB when the application is in Landscape?
And the last use auto layout.

Passing Data from Slide menu to UITableViewController through UINavigationViewController

How can I pass data from UINavigationController to The root UITableViewController?
I have implemented the ECSlidingViewController (https://github.com/edgecase/ECSlidingViewController). User selects one of the cells in the menu that correspond to different urls I want to display information from on my tableView that sitts on top of the UINavigationController. (u know the default combination that u get my dragging UINavigationController to ur storyboard). I am able to get the data from the sliding menu to my navigationController now I am trying to pass that same info on my tableview?
In my menu I have:
UINavigationController *newTopViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"NavigationTop"];
newTopViewController = [(NavigationTopViewController*)newTopViewController initWithCinema:self.myCinema];
In UINaviationController:
- (id)initWithCinema:(Cinema *)cinema {
self = [super init];
if(self) {
_myCinema = [[Cinema alloc] init];
_myCinema = cinema;
}
return self;
}
- (void) viewDidLoad {
[super viewDidLoad];
// this log works I get the info to here.
NSLog(#"url(navigation):%#", self.myCinema.cinemaURL);
//MoviesTableViewController *moviesTableViewController = [[MoviesTableViewController alloc] initWithCinema:self.myCinema];
//UITableViewController *newTopViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"MoviesTable"];
//NavigationTopViewController *newTopViewController = [[NavigationTopViewController alloc] initWithCinema:self.myCinema];
//newTopViewController = [(MoviesTableViewController *)newTopViewController initWithCinema:self.myCinema];
//[self performSegueWithIdentifier:nil sender:self.myCinema];
[self prepareForSegue:nil sender:self.myCinema.cinemaURL];
}
In my UITableView:
- (void)setCinema:(Cinema *)cinema {
// works here too
NSLog(#"Table(setCinema):%#", cinema.cinemaURL);
self.myCinema = [[Cinema alloc] init];
if(!cinema) {
cinema.cityIndex = kAstanaIndex;
cinema.name = kKeruen;
cinema.nameForText = kKeruenText;
cinema.cinemaURL = kKeruenURL;
cinema.cinemaURLTomorrow = kKeruenURLtomorrow;
}
self.myCinema = cinema;
// works here too!!!
NSLog(#"Table(myCinema):%#", self.myCinema.cinemaURL);
}
However its gone in viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
// set delegate to self
self.tableView.delegate = self;
// set loading theater's url
// does not work here: I GET NULL !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
NSLog(#"url(moviesTable):%#", self.myCinema.cinemaURL);
_model = [[MovieModel alloc] initWithURL:self.myCinema.cinemaURL];
}
None of the methods I have tried (commented in Navigation worked...) at least for me. Please give me any suggestions. Thank you in advance.
UINavigationController does not hold any data, but rather a stack of view controllers. I'd recommend you check out frameworks such as the free Sensible TableView. The framework will automatically handle detail view generation and passing data between them. Saves me tons of development time in my projects.

CALayer delegation causes zombie crash -- why?

I am new to Core Animation and having trouble implementing a CALayer object with the drawLayer method in a delegate.
I have narrowed the problem down to a very simple test. I have a main viewController named LBViewController that pushes a secondary viewController called Level2ViewController. In the level 2 controller, in viewWillAppear:, I create a CALayer object with it's delegate=self (i.e. the level 2 controller). Whether or not I actually implement the drawLayer:inContext: method I have the same problem -- when I return to the main viewController I get a zombie crash. In the profiler it appears that the object in trouble is the level 2 viewController object -- which is being dealloc'ed after it's popped.
I've tried using a subclassed CALayer object instead of the delegate and it works fine. If I comment out the delegate assignment it also runs fine. I would like to understand why delegation is causing this problem. Any advice is greatly appreciated.
Here's my code ---
Level2ViewController
#implementation Level2ViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewDidAppear:animated];
CALayer *box1 = [[CALayer alloc] init];
box1.delegate = self; // problem disappears if I comment out this assignment
box1.backgroundColor = [UIColor redColor].CGColor;
box1.frame = CGRectMake(10,10,200,300);
[self.view.layer addSublayer:box1];
[box1 setNeedsDisplay];
}
// makes no difference whether or not this method is defined as long
// as box1.delegate == self
- (void)drawLayer:(CALayer *)theLayer inContext:(CGContextRef)theContext
{
CGContextSaveGState(theContext);
CGContextSetStrokeColorWithColor(theContext, [UIColor blackColor].CGColor);
CGContextSetLineWidth(theContext, 3);
CGContextAddRect(theContext, CGRectMake(5, 5, 40, 40));
CGContextStrokePath(theContext);
CGContextRestoreGState(theContext);
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
The method in LBViewController (the main controller) that pushes the level 2 view controller
- (IBAction)testAction:(id)sender {
Level2ViewController *controller = [[Level2ViewController alloc]
initWithNibName:#"Level2ViewController" bundle:nil];
controller.title = #"Level2";
// this push statement is where the profiler tells me the messaged zombie has been malloc'ed
[self.navigationController pushViewController:controller animated:YES];
[controller release];
}
You may want to set the layer's delegate to nil before the delegate object is released. So in your Leve2ViewController do this:
-(void)viewWillDisappear:(BOOL)animated
{
if (box1) {
box1.delegate = nil;
}
box1 = nil;
}
Obviously this requires, that box1 is turned into a field (so it is accessible in viewWillDisappear:)
Since you create box1in viewWillAppear: the code above uses viewWillDisappear:. Recently, when I ran into a similar problem, I had a separate delegate object in which I used init and dealloc.
Note: You call [super viewDidAppear:animated]; in viewWillAppear. Looks like a typo or copy/paste glitch :-)

Resources