I'm pretty new to objective-c and need some tips for my challenge.
I have 2 view controllers and need to show xml data retrieved from FirstViewController to the TermsViewController.
I'm successful getting user input and retrieve xml objects I need.
But don't know how to show the user name in the TermsViewController.m
Since data is downloaded async, can't figure out how to implement this for IOS 6.
Thanks in advance.
FirstViewController.h
#import <UIKit/UIKit.h>
#interface FirstViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIButton *accessButton;
#property (weak, nonatomic) IBOutlet UITextField *codeField;
#property (weak, nonatomic) NSString *codeUser;
#property (strong, nonatomic) NSString *nameUser;
#property (strong, nonatomic) NSDictionary *xmlDictionary;
#end
TermsViewController.h
#import <UIKit/UIKit.h>
#interface TermsViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *nameLabel;
#property (strong, nonatomic) NSString *nameUserTerms;
#end
FirstViewController.m
#import "FirstViewController.h"
#import "TermsViewController.h"
#import "XMLReader.h"
#interface FirstViewController ()
#property (nonatomic, strong) NSMutableURLRequest *postRequest;
#property NSUInteger responseStatusCode;
#property (nonatomic, strong) NSString *theXML;
#end
#implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)accessButton:(UIButton *)sender {
self.codeUser = self.codeField.text;
NSString *xmlCode = [NSString stringWithFormat:
#"<?xml version='1.0' encoding='utf-8'?>\n"
"<soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>"
"<soap:Body>\n"
"<GetInterview xmlns='http://www.url.com/url.JCV'>\n"
"<Codigo>"
"%#"
"</Codigo>\n"
"</GetInterview>\n"
"</soap:Body>\n"
"</soap:Envelope>", self.codeUser];
NSLog(#"User code is: %#", self.codeUser);
NSLog(#"XML is: %#", xmlCode);
self.postRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://www.url.com/url.JCV/web.url.asmx"]];
[self.postRequest setValue:#"text/xml" forHTTPHeaderField:#"Content-Type"];
[self.postRequest setHTTPMethod:#"POST"];
[self.postRequest setHTTPBody:[NSMutableData dataWithBytes:[xmlCode UTF8String] length:strlen([xmlCode UTF8String])]];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:self.postRequest delegate:self];
if (conn) {
NSLog(#"Connected to: %#", conn);
} else {
NSLog(#"Connection Error");
}
[self.codeField resignFirstResponder];
}
FirstViewController.m connectionDidFinishLoading method
- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
if (self.responseStatusCode == 200) {
NSLog(#"Succeeded! Received %lu bytes of data",[self.theXML length]);
// Parse the XML into a dictionary
NSError *parseError = nil;
self.xmlDictionary = [XMLReader dictionaryForXMLString:self.theXML options:XMLReaderOptionsProcessNamespaces error:&parseError];
NSLog(#"%#", self.xmlDictionary);
//name of the candidate
self.nameUser = [[[[[[[self.xmlDictionary objectForKey:#"Envelope"] objectForKey:#"Body"] objectForKey:#"GetInterviewResponse"] objectForKey:#"GetInterviewResult"] objectForKey:#"Obj"] objectForKey:#"ProfissionalName"] objectForKey:#"text"];
NSLog(#"User name is: %#", self.nameUser);
TermsViewController *nv = [[TermsViewController alloc] init];
nv.nameUserTerms = self.nameUser;
//check
NSLog(#"User name stored: %#", nv.nameUserTerms);
[self performSegueWithIdentifier:#"goToTerms" sender:self];
}
else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error!"
message:#"bla bla."
delegate:self
cancelButtonTitle:#"Try again"
otherButtonTitles:nil];
[alert show];
}
TermsViewController.m
#import "TermsViewController.h"
#interface TermsViewController ()
#end
#implementation TermsViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.nameLabel.text = self.nameUserTerms;
//this check is returning NULL
NSLog(#"User name: %#", self.nameUserTerms);
}
#end
You should use prepareForSegue to exchange data between controllers.
Remove these lines from your code:
TermsViewController *nv = [[TermsViewController alloc] init];
nv.nameUserTerms = self.nameUser;
And put them in a method like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"goToTerms"]) {
TermsViewController *nv = segue.destinationViewController;
nv.nameUserTerms = self.nameUser;
}
}
Related
so I'm trying to get a variable containing the name of a PDF file I wish to open in a UIweb View to show up in a label. I first identify the global variable in a seperate class here:
header:
#import <Foundation/Foundation.h>
extern NSString *PDFNameString;
extern NSString *PDFActualName;
#interface GlobalVars : NSObject
{
}
#property (nonatomic, strong) NSString *PDFActualName;
#property (nonatomic, strong) NSString *PDFNameString;
#end
.m:
#import "GlobalVars.h"
NSString *PDFNameString;
NSString *PDFActualName; //the name of the PDF file
#implementation GlobalVars
{
}
#end
then I have the menu where I have an alert dialog featuring a text field so that the user can input the PDF name:
.h
#import <Foundation/Foundation.h>
#import "GlobalVars.h"
#interface TitleViewController : UIViewController{
NSFileManager *FM1;
}
#property (retain, nonatomic) IBOutlet UIBarButtonItem *OpenPDF;
#property (retain, nonatomic) IBOutlet UIBarButtonItem *ViewPDF;
-(void)OpeningPDF;
-(void)alertView;
#end
.m
#import "TitleViewController.h"
#interface TitleViewController ()
#end
#implementation TitleViewController
UIAlertView * alert;
UITextField *textField;
int StopTheAlerts = 0;
- (void)viewDidLoad
{
[super viewDidLoad];
FM1 = [NSFileManager defaultManager];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)ButtonClicked:(id)sender {
self.OpeningPDF;
}
- (void)dealloc {
[_OpenPDF release];
[_ViewPDF release];
[super dealloc];
}
- (void)OpeningPDF
{
StopTheAlerts = 0;
alert = [[UIAlertView alloc]
initWithTitle:#"Please enter a valid PDF name below:"
message:#"(Please add .PDF on the end!) \n \n"
delegate:self cancelButtonTitle:#"Cancel"
otherButtonTitles:#"ok", nil];
textField = [[UITextField alloc] init];
[textField setBackgroundColor:[UIColor whiteColor]];
textField.delegate = nil;
textField.borderStyle = UITextBorderStyleLine;
textField.frame = CGRectMake(15, 90, 255, 30);
textField.placeholder = #"PDF name";
textField.keyboardAppearance = UIKeyboardAppearanceAlert; //set up an alert box with a text field
[textField becomeFirstResponder];
[alert addSubview:textField];
[alert show];
[alert release];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
PDFNameString = textField.text; //set the PDF name variable to the name entered
PDFActualName = textField.text;
NSArray *Paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *DocumentDir = [Paths objectAtIndex:0];
NSString *TempFilePath = PDFNameString;
PDFNameString = [DocumentDir stringByAppendingPathComponent:TempFilePath];
if([FM1 fileExistsAtPath: PDFNameString]){
_ViewPDF.enabled = true;
}
else {
while(StopTheAlerts <= 0){
UIAlertView *ErrorAlert = [[UIAlertView alloc]
initWithTitle:#"This file dosn't exist!"
message:#"Please reenter the file name!"
delegate:self cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[ErrorAlert show];
[ErrorAlert release];
StopTheAlerts = 1;
}
}
}
#end
This part all works fine, however, when I switch over the the view that contains the UIWebView to actually view the PDF (I've removed that in this part of the code) it has the old "message sent to deallocated instance 0xdb8fca0" error when I try to assign my global variable to the label containing the PDF name, this error also occurs when trying to get the UIWebView to read the PDF using the other global variable.
.h
#import <UIKit/UIKit.h>
#import "GlobalVars.h"
#interface ViewController : UIViewController
#property (retain, nonatomic) IBOutlet UILabel *PDFNameL;
#end
.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_PDFNameL.text = PDFActualName;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)dealloc {
[_PDFNameL release];
[super dealloc];
}
#end
If anyone knows a solution to the problem I would be very happy
thanks
I am tryin to pass the user login emial to other view controllers. It is going from a UITextField to a UILabel but it display null when I log in a user. I want it to display the email name in the UILabel field. Any help? here are my files.
vc1.h
#import <UIKit/UIKit.h>
#interface loginUserViewController : UIViewController
#property (nonatomic, strong) IBOutlet UITextField *email;
#property (nonatomic, retain) IBOutlet UITextField *password;
#property (nonatomic, retain) IBOutlet UIButton *login;
#property (nonatomic,retain) IBOutlet UIButton *registerBtn;
-(IBAction)loginUser:(id)sender;
#end
vc2.h
#import <UIKit/UIKit.h>
#import "loginUserViewController.h"
#interface Home : UIViewController
#property (weak, nonatomic) IBOutlet NSString *getEmail;
#property (weak, nonatomic) IBOutlet UILabel *username;
#property (weak, nonatomic) IBOutlet UIBarButtonItem *Nav;
#property (weak, nonatomic) IBOutlet UIBarButtonItem *logout;
-(IBAction)logout:(id)sender;
-(IBAction)bandHome:(id)sender;
#end
vc2.m
import "Home.h"
#import "loginUserViewController.h"
#interface Home ()
#end
#implementation Home
#synthesize getEmail,username, band1, band2, band3;
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if(self){
}
return self;
}
-(void)viewDidLoad
{
[super viewDidLoad];
// loginUserViewController *object = [[loginUserViewController alloc]init];
// NSString *string = [[NSString alloc] initWithFormat:#"%#", object.email.text];
username.text = getEmail;
}
vc1.m
#import "loginUserViewController.h"
#import "Home.h"
#import "createBandViewController.h"
#interface loginUserViewController ()
#end
#implementation loginUserViewController
#synthesize email, password;
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
}
- (void)viewDidload
{
[super viewDidLoad];
}
-(IBAction)loginUser:(id)sender {
if ([email.text isEqualToString:#""] || [password.text isEqualToString:#""])
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"alert" message:#"Please Fill all the field" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
return;
}
NSMutableString *strURL = [[NSMutableString alloc] initWithFormat:#"Pretend reference/login2.php?email=%#&password=%#", email.text, password.text ];
[strURL setString:[strURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSData *dataURL = [NSData dataWithContentsOfURL:[NSURL URLWithString:strURL]];
NSMutableString *strResult = [[NSMutableString alloc] initWithData:dataURL encoding:NSUTF8StringEncoding];
NSLog(#"logging in");
if ([strResult isEqualToString:#"1"])
{
NSLog(#"Logged in!");
[self performSegueWithIdentifier:#"login" sender:self];
Home *VC;
VC = [self.storyboard instantiateViewControllerWithIdentifier:#"Home"];
[self.navigationController pushViewController:VC animated:YES];
VC.getEmail = self.email.text;
}else
{
// invalid information
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"alert" message:#"Invalide Information" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
return;
}
//email.text = #"";
password.text = #"";
}
-(void)WillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
// Dismisses keyboard by clicking out and hitting return key.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self.view endEditing:YES];
}
-(BOOL)textFieldShouldReturn:(UITextField *) textField {
[textField resignFirstResponder];
return YES;
}
#end
vc2.h
#property (weak, nonatomic) IBOutlet NSString *getEmail;
vc2.m
#synthesize getEmail;
-(void)viewDidLoad
{
[super viewDidLoad];
username.text = getEmail;
}
vc1.m
-(IBAction)loginUser:(id)sender {
if ([email.text isEqualToString:#""] || [password.text isEqualToString:#""])
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"alert" message:#"Please Fill all the field" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
return;
}
else
{
vc2 *VC;
VC = [self.storyboard instantiateViewControllerWithIdentifier:#"vc2Identifier"];
[self.navigationController pushViewController:VC animated:YES];
VC.getEmail = self.email.text
}
}
You don't need to alloc and init the view controller where you have to get the data , but you have to pass the data from vc1 to vc2 and use the variable of vc2 in vc1 , And what your were doing was using the vc1 value in vc2 . And you were allocating the LoginViewController , and in viewDidUnload method , you have set email textfield as nil . that is why you were getting nil value in vc2
I am in the middle of an app re-design and am refactoring and extending my model.
One aspect of my apps model is that the app retrieves data from a web service and populates the model.
My question is: Should my model objects have the capability to implement NSURLSession or should I rely on the VC to provide the connection?
I'm asking from a best practices standpoint. What's the best way to think about this? Should the model be totally on its own or should it have network access?
One consideration is that these model objects are essentially useless without data from the network, meaning data from the Internet is a fundamental aspect of their existence.
If we take SOLID — especially the S for Single Responsible Principle — in account, it becomes obvious, that neither the VC nor the model should do the networking:
a VC's single responsible would be to handle views
the model's purpose would be to hold data
networking should be done by a third class, a networking controller.
This three points will fulfill SOLID, but how do you get data from the network into model objects show on a view?
Well, this depends on your overall architectural design on the app, but a common approach would be to use callback — either a delegate protocol or a block — with your network controller.
You create a network controller in the app delegate and pass it from view controller to view controller via properties to any place in the app were newly fetched data is needed. I wouldn't use a singleton here, as that violates O, I & D of SOLID.
Add a class method to your model +(NSArray *)modelObjectsFromDictionaries:(NSArray *) or similar.
In the view controller you can now do
-(void)viewDidLoad
{
[super viewDidLoad];
__weak typeof(self) weakSelf = self;
[self.networkController fetchModels:^(NSArray *modelDictionaries, NSError *error){
typeof(weakSelf) self = weakSelf;
if(self) {
if(!error){
[self.dataSource addOrUpdateData:[Model modelObjectsFromDictionaries:modelDictionaries]];
} else {
// error handling
}
}
}];
}
This is just a starting point. For more complicated APIs it might be useful to use an api controller that itself uses the networking controller and maybe a persistence controller.
Although instead of a Model class method you might want to use some sort of mapping and abstract factory pattern… But all this things would require more information about your app and are out of the scope for this question.
Update:
I created a sample project to demonstrate this.
It is slightly different than what I say above:
As it uses a table view, I am using a data source class to populate it. Instead of the view controller the data source will tell the network controller to fetch new data.
I am using OFAPopulator for this, a library written by me to populate table views and collection views in a SOLID-conform fashion, or to «Keep view controllers clean and MVC smart».
#import "AppDelegate.h"
#import "VSNetworkController.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self.window.rootViewController setValue:[[VSNetworkController alloc] initWithBaseURL:[NSURL URLWithString:#"http://api.goeuro.com/api/v2/"]]
forKey:#"networkController"];
return YES;
}
#end
// VSNetworkController.h
#import <Foundation/Foundation.h>
#interface VSNetworkController : NSObject
-(instancetype)initWithBaseURL:(NSURL *) baseURL;
-(void)suggestionsForString:(NSString *)suggestionString
responseHandler:(void(^)(id responseObj, NSError *error))responseHandler;
#end
// VSNetworkController.m
#import "VSNetworkController.h"
#interface VSNetworkController ()
#property (nonatomic, strong) NSURL *baseURL;
#end
#implementation VSNetworkController
-(instancetype)initWithBaseURL:(NSURL *)baseURL
{
self = [super init];
if (self) {
_baseURL = baseURL;
}
return self;
}
-(void)suggestionsForString:(NSString *)suggestionString
responseHandler:(void(^)(id responseObj, NSError *error))responseHandler
{
NSURL *url = [self.baseURL URLByAppendingPathComponent:[NSString stringWithFormat:#"position/suggest/en/%#", suggestionString]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response,
NSData *data,
NSError *connectionError) {
responseHandler([NSJSONSerialization JSONObjectWithData:data options:0 error:nil], connectionError);
}];
}
#end
// VSLocationSuggestion.h
#import <Foundation/Foundation.h>
#import CoreLocation;
#interface VSLocationSuggestion : NSObject
#property (nonatomic, copy, readonly) NSString *name;
#property (nonatomic, copy, readonly) NSString *country;
#property (nonatomic, strong, readonly) CLLocation *position;
+(NSArray *)suggestionsFromDictionaries:(NSArray *)dictionaries;
#end
// VSLocationSuggestion.m
#import "VSLocationSuggestion.h"
#interface VSLocationSuggestion ()
#property (nonatomic, copy) NSString *name;
#property (nonatomic, copy) NSString *country;
#property (nonatomic, strong) CLLocation *position;
#end
#implementation VSLocationSuggestion
+(NSArray *)suggestionsFromDictionaries:(NSArray *)dictionaries
{
NSMutableArray *array = [#[] mutableCopy];
[dictionaries enumerateObjectsUsingBlock:^(NSDictionary *suggestionDict, NSUInteger idx, BOOL *stop) {
[array addObject:[[self alloc] initWithDictionary:suggestionDict]];
}];
return [array copy];
}
-(instancetype)initWithDictionary:(NSDictionary *)dict
{
self = [super init];
if (self) {
_name = dict[#"name"];
_country = dict[#"country"];
CLLocationDegrees latitude = [dict[#"geo_position"][#"latitude"] doubleValue];
CLLocationDegrees longitude =[dict[#"geo_position"][#"longitude"] doubleValue];
_position = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
}
return self;
}
#end
// VSSuggestionDataSource.h
#import <Foundation/Foundation.h>
#import <OFADataProvider.h>
#class VSNetworkController;
#interface VSSuggestionDataSource : NSObject <OFADataProvider>
-(instancetype)initWithNetworkController:(VSNetworkController *)networkController;
-(void)setNewSuggestions:(NSArray *)suggetsions;
-(void)enteredStringForSuggestions:(NSString *)suggestionString;
#end
// VSSuggestionDataSource.m
#import "VSSuggestionDataSource.h"
#import "VSNetworkController.h"
#import "VSLocationSuggestion.h"
#interface VSSuggestionDataSource ()
#property (nonatomic, copy) void (^available)(void);
#property (nonatomic, strong) VSNetworkController *networkController;
#end
#implementation VSSuggestionDataSource
#synthesize sectionObjects;
-(instancetype)initWithNetworkController:(VSNetworkController *)networkController
{
self = [super init];
if (self) {
_networkController = networkController;
}
return self;
}
-(void)dataAvailable:(void (^)(void))available
{
_available = available;
}
-(void)setNewSuggestions:(NSArray *)suggetsions
{
self.sectionObjects = suggetsions;
self.available();
}
-(void)enteredStringForSuggestions:(NSString *)s
{
__weak typeof(self) weakSelf = self;
[self.networkController suggestionsForString:s responseHandler:^(NSArray *responseObj, NSError *error) {
typeof(weakSelf) self = weakSelf;
if (self) {
if (!error && responseObj) {
NSArray *suggestion = [VSLocationSuggestion suggestionsFromDictionaries:responseObj];
[self setNewSuggestions:suggestion];
}
}
}];
}
#end
// ViewController.h
#import <UIKit/UIKit.h>
#class VSNetworkController;
#interface ViewController : UIViewController
#property (nonatomic, strong) VSNetworkController *networkController;
#end
// ViewController.m
#import "ViewController.h"
#import "VSLocationSuggestion.h"
#import <OFAViewPopulator.h>
#import <OFASectionPopulator.h>
#import "VSSuggestionDataSource.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property (strong, nonatomic) OFAViewPopulator *viewPopultor;
#property (strong, nonatomic) VSSuggestionDataSource *dataSource;
- (IBAction)textChanged:(UITextField *)sender;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.dataSource = [[VSSuggestionDataSource alloc] initWithNetworkController:self.networkController];
OFASectionPopulator *sectionPopulator = [[OFASectionPopulator alloc] initWithParentView:self.tableView
dataProvider:self.dataSource
cellIdentifier:^NSString *(id obj, NSIndexPath *indexPath) {
return #"Cell";
} cellConfigurator:^(VSLocationSuggestion *obj, UITableViewCell *cell, NSIndexPath *indexPath) {
cell.textLabel.text = obj.name;
}];
sectionPopulator.objectOnCellSelected = ^(VSLocationSuggestion *suggestion, UIView *cell, NSIndexPath *indexPath ){
NSString * string =[NSString stringWithFormat:#"%#, %# (%f %f)", suggestion.name, suggestion.country, suggestion.position.coordinate.latitude, suggestion.position.coordinate.longitude];
UIAlertController *avc = [UIAlertController alertControllerWithTitle:#"Selected" message:string preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction
actionWithTitle:NSLocalizedString(#"Cancel", #"Cancel action")
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action)
{
;
}];
[avc addAction:cancelAction];
[self presentViewController:avc animated:YES completion:NULL];
};
self.viewPopultor = [[OFAViewPopulator alloc] initWithSectionPopulators:#[sectionPopulator]];
}
- (IBAction)textChanged:(UITextField *)sender
{
NSString *s = sender.text;
if ([s length]) {
[self.dataSource enteredStringForSuggestions:s];
}
}
#end;
I made this code available on github: https://github.com/vikingosegundo/LocationSugesstion
Data is not being passed from one VC to another, can't for the life of me figure it out. I'm trying to pass an NSURL or NSURLRequest and when I log out the request/url object on the second VC, I get null.
First VC.h
#import <UIKit/UIKit.h>
#import "ILAuthClient.h"
#import "ILAuthLoginViewController.h"
#interface ILViewController : UIViewController
#property (strong, nonatomic) NSString *string;
#property (strong, nonatomic) NSURL *request;
#end
First VC.m (relevant section)
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"authLogin"]){
NSURL *url = [self authenticateWithInstagram];
ILAuthLoginViewController *authModal = [[ILAuthLoginViewController alloc]init];
authModal.delegate = self;
authModal.url = url;}
Second VC.h
#import <UIKit/UIKit.h>
#interface ILAuthLoginViewController : UIViewController <UIWebViewDelegate>
#property (strong, nonatomic) IBOutlet UIWebView *webView;
#property (strong, nonatomic) NSURLRequest *request;
#property (strong, nonatomic) NSURL *url;
#property (strong, nonatomic) NSString *string;
#end
Second VC.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.webView.delegate = self;
self.request = [[NSURLRequest alloc]initWithURL:self.url];
[self.webView loadRequest:self.request];
NSLog(#"Request %#", self.request);
}
When you enter prepareForSegue your second view controller has already been allocated for you and is available as the destinationViewController property on the segue. You are allocating a new one and assigning properties but this object isn't used.
Your method should be
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"authLogin"]){
NSURL *url = [self authenticateWithInstagram];
ILAuthLoginViewController *authModal = (ILAuthLoginViewController *)segue.destinationViewController;
authModal.delegate = self;
authModal.url = url;
}
}
This line ...
ILAuthLoginViewController *authModal = [[ILAuthLoginViewController alloc]init];
should be changed to this
ILAuthLoginViewController * authModal = (ILAuthLoginViewController *) segue.destinationViewController;
The one you are allocing isn't the one the storyboard is presenting
Two things to check for.
1.Your call is wrong while passing through segue. It should be
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"authLogin"]){
NSURL *url = [self authenticateWithInstagram];
ILAuthLoginViewController *authModal = (ILAuthLoginViewController *)segue.destinationViewController;
authModal.delegate = self;
authModal.url = url;
}
}
2.Make sure your url string is well formed.
NSURL *url = [NSURL URLWithString:[#"YOURURL" stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
Hope its helpful.
This question already has answers here:
How do I create delegates in Objective-C?
(20 answers)
Closed 9 years ago.
On iOS, how do I create a delegate (user defined)?
First define a declare a delegate like this -
#protocol IconDownloaderDelegate;
Then create a delegate object like this -
#interface IconDownloader : NSObject
{
NSIndexPath *indexPathInTableView;
id <IconDownloaderDelegate> delegate;
NSMutableData *activeDownload;
NSURLConnection *imageConnection;
}
Declare a property for it -
#property (nonatomic, assign) id <IconDownloaderDelegate> delegate;
Define it -
#protocol IconDownloaderDelegate
- (void)appImageDidLoad:(NSIndexPath *)indexPath;
#end
Then you can call methods on this delegate -
[delegate appImageDidLoad:self.indexPathInTableView];
Here is the complete source code of the image downloader class -
.h file -
#class AppRecord;
#class RootViewController;
#protocol IconDownloaderDelegate;
#interface IconDownloader : NSObject
{
AppRecord *appRecord;
NSIndexPath *indexPathInTableView;
id <IconDownloaderDelegate> delegate;
NSMutableData *activeDownload;
NSURLConnection *imageConnection;
}
#property (nonatomic, retain) AppRecord *appRecord;
#property (nonatomic, retain) NSIndexPath *indexPathInTableView;
#property (nonatomic, assign) id <IconDownloaderDelegate> delegate;
#property (nonatomic, retain) NSMutableData *activeDownload;
#property (nonatomic, retain) NSURLConnection *imageConnection;
- (void)startDownload;
- (void)cancelDownload;
#end
#protocol IconDownloaderDelegate
- (void)appImageDidLoad:(NSIndexPath *)indexPath;
#end
.m file -
#import "IconDownloader.h"
#import "MixtapeInfo.h"
#define kAppIconHeight 48
#define TMP NSTemporaryDirectory()
#implementation IconDownloader
#synthesize appRecord;
#synthesize indexPathInTableView;
#synthesize delegate;
#synthesize activeDownload;
#synthesize imageConnection;
#pragma mark
- (void)dealloc
{
[appRecord release];
[indexPathInTableView release];
[activeDownload release];
[imageConnection cancel];
[imageConnection release];
[super dealloc];
}
- (void)startDownload
{
self.activeDownload = [NSMutableData data];
// alloc+init and start an NSURLConnection; release on completion/failure
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:
[NSURLRequest requestWithURL:
[NSURL URLWithString:appRecord.mixtape_image]] delegate:self];
self.imageConnection = conn;
[conn release];
}
- (void)cancelDownload
{
[self.imageConnection cancel];
self.imageConnection = nil;
self.activeDownload = nil;
}
#pragma mark -
#pragma mark Download support (NSURLConnectionDelegate)
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.activeDownload appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// Clear the activeDownload property to allow later attempts
self.activeDownload = nil;
// Release the connection now that it's finished
self.imageConnection = nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Set appIcon and clear temporary data/image
UIImage *image = [[UIImage alloc] initWithData:self.activeDownload];
self.appRecord.mixtape_image_obj = image;
self.activeDownload = nil;
[image release];
// Release the connection now that it's finished
self.imageConnection = nil;
// call our delegate and tell it that our icon is ready for display
[delegate appImageDidLoad:self.indexPathInTableView];
}
#end
and here is how we use it -
#import "IconDownloader.h"
#interface RootViewController : UITableViewController <UIScrollViewDelegate, IconDownloaderDelegate>
{
NSArray *entries; // the main data model for our UITableView
NSMutableDictionary *imageDownloadsInProgress; // the set of IconDownloader objects for each app
}
in .m file -
- (void)startIconDownload:(AppRecord *)appRecord forIndexPath:(NSIndexPath *)indexPath
{
IconDownloader *iconDownloader = [imageDownloadsInProgress objectForKey:indexPath];
if (iconDownloader == nil)
{
iconDownloader = [[IconDownloader alloc] init];
iconDownloader.appRecord = appRecord;
iconDownloader.indexPathInTableView = indexPath;
iconDownloader.delegate = self;
[imageDownloadsInProgress setObject:iconDownloader forKey:indexPath];
[iconDownloader startDownload];
[iconDownloader release];
}
}
here is delegate gets called automatically -
// called by our ImageDownloader when an icon is ready to be displayed
- (void)appImageDidLoad:(NSIndexPath *)indexPath
{
IconDownloader *iconDownloader = [imageDownloadsInProgress objectForKey:indexPath];
if (iconDownloader != nil)
{
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:iconDownloader.indexPathInTableView];
// Display the newly loaded image
cell.imageView.image = iconDownloader.appRecord.appIcon;
}
}
This is basic concepts to create a own delegate
Delegates are very useful to control transfer within the array of view controllers in app manually. Using delegates you can manage the control flow very well.
here is small example of own delegates....
Create a protocol class.... (.h only)
SampleDelegate.h
#import
#protocol SampleDelegate
#optional
#pragma Home Delegate
-(NSString *)getViewName;
#end
Import above protocol class in the class whom you want to make delegate of another class. Here in my ex. I m using AppDelegate to make delegate of The HomeViewController's Object.
also add above DelegateName in Delegate Reference < >
ownDelegateAppDelegate.h
#import "SampleDelegate.h"
#interface ownDelegateAppDelegate : NSObject <UIApplicationDelegate, SampleDelegate> {
}
ownDelegateAppDelegate.m
//setDelegate of the HomeViewController's object as
[homeViewControllerObject setDelegate:self];
//add this delegate method definition
-(NSString *)getViewName
{
return #"Delegate Called";
}
HomeViewController.h
#import
#import "SampleDelegate.h"
#interface HomeViewController : UIViewController {
id<SampleDelegate>delegate;
}
#property(readwrite , assign) id<SampleDelegate>delegate;
#end
HomeViewController.h
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UILabel *lblTitle = [[UILabel alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
lblTitle.text = [delegate getViewName];
lblTitle.textAlignment = UITextAlignmentCenter;
[self.view addSubview:lblTitle];
}