Data Doesn't Load Unless UIButton Clicked - objective-c

This might be a strange case so I apologize in advance if my problem or solution is unclear:
I have a LoginViewController that fetches a users Facebook profile picture, username, email, etc. I then have it segue to a HomeViewController that displays some objects, other items, and a UIView that shows the users profile picture.
The strange part is that the UIImage that i create only gets transferred when I use a UIButton. I can not seem to get the image to be sent to the HomeViewController any other way. I even set up a GCP to have it try and wait in order for Facebook to deliver the information - still nothing. Below is the code that I have for the LoginViewController.m. If anyone has any idea on why this is happening I would be extremely grateful. thank you!
#import "LoginViewController.h"
#import <QuartzCore/QuartzCore.h>
#interface LoginViewController ()
- (void)toggleHiddenState:(BOOL)shouldHide;
#end
#implementation LoginViewController
#synthesize profPicture;
- (void)viewDidLoad {
[super viewDidLoad];
[self toggleHiddenState:YES];
self.lblLoginStatus.text = #"";
self.loginButton.readPermissions = #[#"public_profile", #"email"];
self.loginButton.delegate = self;
// Do any additional setup after loading the view.
}
-(void)toggleHiddenState:(BOOL)shouldHide{
self.lblUsername.hidden = shouldHide;
self.lblEmail.hidden = shouldHide;
self.profilePicture.hidden = shouldHide;
self.loggedinwallpaper.hidden = shouldHide;
self.FBlogout.hidden = shouldHide;
}
-(void)loginViewShowingLoggedInUser:(FBLoginView *)loginView{
self.lblLoginStatus.text = #"";
[self toggleHiddenState:NO];
}
-(void)loginViewShowingLoggedOutUser:(FBLoginView *)loginView{
self.lblLoginStatus.text = #"";
[self toggleHiddenState:YES];
}
-(void)loginViewFetchedUserInfo:(FBLoginView *)loginView user:(id<FBGraphUser>)user{
NSLog(#"%#", user);
self.profilePicture.profileID = user.objectID;
self.lblUsername.text = user.name;
self.lblEmail.text = [user objectForKey:#"email"];
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void){
// Create Facebook Profile Picture from User ID url
NSString *pic_link = [NSString stringWithFormat:#"http://graph.facebook.com/%#/picture?width=300&height=300", user.objectID];
NSURL *pic_url = [NSURL URLWithString:pic_link];
profPicture = [UIImage imageWithData: [NSData dataWithContentsOfURL:pic_url]];
dispatch_async(dispatch_get_main_queue(), ^(void){
//Main Thread : UI Updates
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *homeViewController = (UIViewController *)[storyboard instantiateViewControllerWithIdentifier:#"HomeViewController"];
[self performSelector:#selector(prepareForSegue:sender:) withObject:nil afterDelay:1.0 ];
[self presentViewController:homeViewController animated:YES completion:nil];
});
});
}
-(void)loginView:(FBLoginView *)loginView handleError:(NSError *)error{
NSLog(#"%#", [error localizedDescription]);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
HomeViewController *homeviewController = segue.destinationViewController;
homeviewController.homepic = profPicture;
}
#end

From the code you shared I'd assume that the button you mentioned worked because you wired that up in the Storyboard with a segue, right? (Dragged an arrow to the next VC?)
The issue with your code is that here
[self performSelector:#selector(prepareForSegue:sender:) withObject:nil afterDelay:1.0 ];
you are triggering prepareForSegue:sender: on your own without the necessary parameters - you don't have a segue to prepare for as you aren't even segueing to the other view controller. So when HomeViewController *homeviewController = segue.destinationViewController; is executed segue is nil so the image can't be set.
You should be able to fix this by replacing your code which runs on the main thread with this:
dispatch_async(dispatch_get_main_queue(), ^(void){
// Main Thread : UI Updates
[self performSegueWithIdentifier:#"<insert segue identifier here>" sender:self];
});
Make sure to set a name in your Storyboard for the segue between the view controllers and use that identifier here. (See the Apple Docs)

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
HomeViewController *homeviewController = segue.destinationViewController;
homeviewController.homepic = [UIImage alloc] init];
homeviewController.homepic = profPicture;
}

Related

Presenting popover in UITabBarController using UIBarButtonItem iOS9

I would like to present a popover from UIBarButtonItem present in UITabBarController using objectiveC in iOS9. This popover is a UITableViewController. I have coded it in the following way
- (IBAction)MenuButtonPopOverTouch:(id)sender {
LogoutTableViewController* content = [[LogoutTableViewController alloc] init];
content.modalPresentationStyle = UIModalPresentationPopover;
[self presentViewController:content animated:YES completion:nil];
UIPopoverPresentationController *PopOverPresentation = [content popoverPresentationController];
PopOverPresentation.permittedArrowDirections = UIPopoverArrowDirectionDown;
}
I think i have missed the content size of the popover but don't know how to initialize it. Any help is appreciated. Attaching a preview of my storyboard if needed anything else please let me know
I found answer to my question here is the solution
- (IBAction)MenuPopOver:(id)sender {
[self performSegueWithIdentifier:#"CustomerMenu" sender:self.MenuBarButtonItem];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
NSString *popoverIdentifier = segue.identifier;
if([popoverIdentifier isEqualToString:#"CustomerMenu"]){
UIViewController *dvc = segue.destinationViewController;
dvc.preferredContentSize = CGSizeMake(150, 50);
UIPopoverPresentationController *ppc = dvc.popoverPresentationController;
if (ppc) {
ppc.delegate = self;
}
}
}
-(UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller{
return UIModalPresentationNone;
}
I found it through this link PopoverPresentationController
It has been tested as well

Remove subview and send control back

I am invoking "HelpviewController" from UIViewController using following code, which is working fine.
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"InnerHelpPageViewController"];
self.pageViewController.dataSource = self;
InnerHelpViewController *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];
Inside my new controller InnerHelpViewController I have done button which should remove this newly added view and send control back to initiated page.
- (IBAction)unwindToMenuFromInnerHelp:(id)sender {
[self.view removeFromSuperview];
}
This call removing the newly added view, but the problem is "MenuController" is frozen. I couldn't do any clicks on it. Any help?
To explain flow--> I have menu screen where one button with name "help" --> When user clicks on this help button first snippet of code in this question executes and shows HelpViewController-->Once done with help, user clicks "Done" button--> Which should close the HelpViewController and move to "menu" screen.
Implement protocol method in InnerHelpViewController.h file class
#protocol InnerHelpViewControllerDelegate
-(void)removeCustomView;
#end
#interface InnerHelpViewController : UIViewController{
}
#property(nonatomic, weak) id<InnerHelpViewControllerDelegate> delegate.
In InnerHelpViewController.m file
#synthesize delegate;
- (IBAction)unwindToMenuFromInnerHelp:(id)sender {
[delegate removeCustomView];
}
in MenuController .h file Adopt InnerHelpViewControllerDelegate.
#interface MenuController : UIViewController<InnerHelpViewControllerDelegate>{
}
Now Confirm your delegate in MenuController.m file while helpviewcontroller object creation.
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"InnerHelpPageViewController"];
self.pageViewController.dataSource = self;
InnerHelpViewController *startingViewController = [self viewControllerAtIndex:0];
startingViewController.delegate = self;
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];
//Implement here delegate method
-(void)removeCustomView{
[self.pageViewController removeFromSuperview]
}

ImagePickerController crash presentViewController when called in UIStoryboardPopoverSegue

I have a viewcontroller called via UIStoryboardPopoverSegue and inside there is a button to call the imagePickerController, it's ok for the first call but the second time it crash.
The code is use is ok when it is not through UIStoryboardPopoverSegue.
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *image=[info objectForKey:UIImagePickerControllerOriginalImage];
UIImageWriteToSavedPhotosAlbum (image, nil, nil , nil);
[self dismissViewControllerAnimated:YES completion:nil];
}
-(IBAction)takephoto:(id)sender
{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
self.imagePicker.delegate=self;
self.imagePicker.sourceType=UIImagePickerControllerSourceTypeCamera;
[self presentViewController:imagePicker animated:YES completion:nil];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
if (!self.imagePicker)
{
self.imagePicker = [[UIImagePickerController alloc] init];
}
}
I enabled NSZobmbie to show any log that can help me tracing it.
* -[UIImagePickerController isKindOfClass:]: message sent to
deallocated instance 0x1eb3b700
Your UIImagePickerController is released and then attempted to be accessed later - so crashes!
To fix it, make the UIImagePickerController a strongly referenced property of the owning instance:
#property (strong, nonatomic) UIImagePickerController *imagePicker;
initialise it once:
if (!self.imagePicker) self.imagePicker = [[UIImagePickerController alloc] init];
and use:
[self.imagePicker doStuff]
for access.
That should solve it.
EDIT
if ([[segue identifier]isEqualToString:#"tcwindshield"]) {
self.ips = [segue destinationViewController];
self.ips.delegate = self
self.ips.strStatValue=#"WindShield";
}

Grand Central Dispatch: App crashes on instance member assignment

To start with it all works without using the the GCD but I want this happening in a separate thread so trying GCD. I've got a login screen where on pressing the login button i've got the following action:
- (void)login
{
dispatch_queue_t buckyballLoginFetcherQ = dispatch_queue_create("Login Queue", NULL);
dispatch_async(buckyballLoginFetcherQ, ^
{
NSDictionary *resultDictionary = [MyService login:self.name.text password:self.password.text];
self.userDetails = [resultDictionary valueForKey:USER_DETAILS_ATTRIBUTE];
[self performSegueWithIdentifier:#"Login" sender:self];
});
}
In MyService method being called above:
+ (NSDictionary *)executeRequest:(NSDictionary *)requestDictionary
{
// Prepare the URL request and do the following
NSData *results = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&urlRequestError];
// Process results
...
}
NOW the bit that crashes:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"Login"])
{
MyDestinationTableViewController *myDestinationTableViewController = nil;
UITabBarController *tbc = (UITabBarController *)[segue destinationViewController];
for (UIViewController *vc in [tbc viewControllers])
{
if ([vc isKindOfClass:[UINavigationController class]])
{ // in our case all view controlers are navigation controllers :-)
UINavigationController *nc = (UINavigationController *)vc;
if ([[[nc viewControllers] lastObject] isKindOfClass:[BuckyballsTableViewController class]])
{
myDestinationTableViewController = [[nc viewControllers] lastObject];
/**************CRASH LINE************/
buckyballsTableViewController.userDetails = self.userDetails;
}
}
}
}
Again without GCD it works, but it holds up screen so i'd want to do it asynchronously. Is it the instance member causing a problem? OR do i need to use it differently or do more with it? Thank you...
Only the main thread may manipulate the UI, so use this code fragment to call those bits on the main thread:
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:#"Login" sender:self];
});

Objective c: Protocol + Delegate to pass data back from Login form in a Modal View to an tab bar controller view

I'm developing a tab bar based app for iPhone.
The flow is the following: when the app runs, I throw up the modal view with the login form:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
tabBarController.delegate = self;
// Add the tab bar controller's view to the window and display.
self.window.rootViewController = self.tabBarController;
[self addTabBarArrow];
LoginViewController *loginViewController = [[LoginViewController alloc] init];;
[window addSubview:tabBarController.view];
[self.tabBarController presentModalViewController:loginViewController animated:YES];
[window makeKeyAndVisible];
return YES; }
In the log in modal view LoginViewController.h (child) I've got a protocol implemented:
#protocol PassUserInfoDelegate <NSObject>
#required
- (void) passUserInfo: (NSString *)string;
#end
When the user fills out the form, I create a NSURLConnection, and in the connectionDidFinishLoading method I get the user values from an JSON request:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *respuestaServidor = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
self.responseData = nil;
NSDictionary *dictionary = [respuestaServidor JSONValue];
idJson = [dictionary objectForKey:#"id"];
NSString *user_loginJson = [dictionary objectForKey:#"user_login"];
if ([idJson isEqualToString:#"null"] && [user_loginJson isEqualToString:#"null"]) {
NSLog(#"Login incorrecto");
} else {
NSLog(#"Procedo a loguear usuario");
}
[indicator stopAnimating];
[indicator release];
}
In HomeViewController.h (parent) I've got the delegation:
#interface HomeViewController : UIViewController <PassUserInfoDelegate> {
LoginViewController *protocolTest;
IBOutlet UILabel *nombreUsuario;
NSString *usuario;
}
#property (nonatomic, retain) IBOutlet UILabel *nombreUsuario;
#property (copy) NSString *usuario;
- (void) passUserInfo:(NSString *)string;
#end
and in the HomeViewController.m I implement the Protocol method:
- (void) passUserInfo:(NSString *)jSonString
{
userName.text = [[NSString alloc] initWithFormat:#"Welcome %#", jSonString];
}
and in the viewDidAppear method I call the loginSuccess method implemented in the LoginViewController class
-(void) viewDidAppear:(BOOL)animated{
protocolTest = [[LoginViewController alloc] init];
[protocolTest setDelegate:self];
[protocolTest loginSuccess];
}
loginSuccess method implemented in the LoginViewController class:
- (void)loginSuccess
{
[[self delegate] passUserInfo:idJson];
}
and it should pass the idJson value to the HomeViewController (parent).
The problem is that when I dismiss the modal view form, the idJson value is "NIL", so then in the HomeViewController I can't get this value. If I make this instead:
[[self delegate] passUserInfo:#"hello"];
I get the hello string in the HomeViewController (parent)
What am I doing wrong??
Thanks in advance!!!
Your problem is that instead of using the existing LoginViewController that has the actual data. Your viewWillAppear is creating a new one that never made the connection and getting its empty data.
First in the app delegate, you need to set your HomeViewController (the one in the tabbar) as the delegate to the LoginViewController that you're presenting.
Then, from connectionDidFinishLoading: you should be calling the [delegate passUserInfo:idJson]; to inform the HomeVC that the login screen got data.
You HomeVC's passUserInfo: method should probably dismiss the LoginVC with [self.tabBarController dismissModalViewControllerAnimated:YES]; (Since the login view was presented from the tabbar controller).