I can't figure out why my segue.identifier is always returning null. I set the segue identifiers in the storboard.
ViewController1
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"prepared %#",segue.identifier);
if([[segue identifier] isEqualToString:#"segue1"] ){
NSLog(#"segue is equal to 1");
}
}
ViewController2
- (IBAction)unwindFromSegue:(UIStoryboardSegue *)segue {
NSLog(#"unwinded %#",segue.identifier);
}
The log message is always null so if statement is never true. Any thoughts why i cant get the identifier?
EDIT:
I made a whole new project for testing. It's a single view application with ViewController and SecondViewController. In the storyboard I made a popover segue connection from a button in View Controller to SecondViewController and set the segue identifier to segue1.
On SecondViewController I made a back button and connected it to the unwindFromSegue in my ViewController. I also added prepareForSegue in the SecondViewController.
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)unwindFromSegue:(UIStoryboardSegue *)segue {
NSLog(#"unwinded %#",segue.identifier);
}
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
#end
SecondViewController.m
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
- (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.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//was just testing unwindFromSegue here. Didn't mean to post here,
//but I will keep it in with an answer referring to it
//- (IBAction)unwindFromSegue:(UIStoryboardSegue *)segue{
//NSLog(#"unwind in second %#",segue.identifier);
//}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
NSLog(#"prepare %#",segue.identifier);
}
#end
Hope this helps. Thanks
When you set the segue in the storyboard you also have to assign it an identifier. In your case "segue1".
Why do you have an unwindFromSegue: method in SecondViewController? You're not unwinding to that controller, and it has the same name as the one in ViewController. That could be your problem. Take that one out and see if that fixes the problem.
Related
I have a UIViewController several segues deep that when the use is finished, should unwind and take them back to the DashboardViewController.
I created the unwindToDashboard method in the Dashboard and hooked a button up to the Exit in my FinishViewController. So that when its clicked will fire the unwind action.
That works fine.
But I need to pass back data to the Dashboard from the FinishViewController.
So I created a delegate ProcessDataDelegate for the FinishViewController and made the Dashboard conform to it.
However, the delegate method in the Dashboard is NOT called.
Can anyone tell me what I have done wrong?
DashboardViewController.m
#import "FinishViewController.h"
#interface DashboardViewController () <ProcessDataDelegate>{
FinishViewController *fm;
}
#end
#implementation DashboardViewController
- (void)viewDidLoad {
[super viewDidLoad];
if(!fm){
fm = [[FinishViewController alloc] init];
}
fm.delegate = self;
}
- (IBAction)unwindToDashboard:(UIStoryboardSegue *)unwindSegue {
//empty
}
#pragma mark PROTOCOL METHODS
-(void) didFinishWithResults:(NSDictionary*) dictionary{
NSLog(#"Dashboard method called didFinishWithResults");
}
#end
FinishViewController.h
#class FinishViewController;
#protocol ProcessDataDelegate <NSObject>
#required
- (void) didFinishWithResults: (NSDictionary*)dictionary;
#end
#interface FinishViewController : UIViewController
#property (nonatomic, weak) id <ProcessDataDelegate> delegate;
#end
FinishViewController.m
#interface FinishViewController ()
#end
#implementation FinishViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NSLog(#"fired via the button to the exit--- Segue: %#", [segue identifier]);
[delegate didFinishWithResults:nil ];
}
#end
You need pass your delegate in prepareForSegue method of your DashboardViewController, there get the destinationViewController and cast to FinishViewController if the identifier is equal to your expected segue identifier
Something like this
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NSLog(#"fired via the button to the exit--- Segue: %#", [segue identifier]);
if([[segue identifier] isEqualToString:#"YourSegueIdentifier"])
{
((FinishViewController*)[segue destinationViewController]).delegate = self
}
}
I make a retain cycle , but in profiling , the tools seems can't find this obivious retain cycle
first , the ViewController will retain the SubViewController as property subVC, and be set as the delegate of SubViewController.
#interface ViewController ()<TestDelegate>
#property(nonatomic,strong) UIViewController* subVC;
#end
#implementation ViewController
- (void)dealloc
{
NSLog(#"ViewController dealloc");
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
SubViewController* subVC = [[SubViewController alloc] init];
subVC.delegate = self;
self.subVC = subVC;
[self presentViewController:subVC animated:YES completion:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)didSelect
{
}
#end
And in the SubViewController, the delegate is been set as the strong property to retain the delegate
#protocol TestDelegate <NSObject>
#optional
- (void)didSelect;
#end
#interface SubViewController : UIViewController
#property(nonatomic,strong) id<TestDelegate> delegate;
#end
#interface SubViewController ()
#end
#implementation SubViewController
- (void)dealloc
{
NSLog(#"SubViewController dealloc");
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (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 {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#end
OK , Now the tools seems working only if i switch between the panel between the All Heap & Leak Checks. And If i dont switch in them . the retain cycle will never gonna be found.
im new to iOS and its developing .there i have used iOS delegates to pass values in between view controllers
1. Essentialinfocontroller - its got TableView
2. detailcontroller -
i want to pass values of Essentialinfocontroller to detailcontroller
to do that i used delegates but nothing print on console please help me.
Essentialinfocontroller.h
#import <UIKit/UIKit.h>
#protocol sendTestData <NSObject>
-(void)sendDataToA:(NSArray *)array;
#end
#interface Essentialinfocontroller : UIViewController<UITableViewDataSource,UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *info;
#property (nonatomic,strong) NSDictionary * courses;
#property (nonatomic, strong)NSArray *coursekeys;
#property(nonatomic,strong) NSString* customeLink;
#property (nonatomic,retain)NSArray * array;
#property(nonatomic,assign)id delegate;
#end
Essentialinfocontroller.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row==0){
[self giveValuestoNSmutableArray];
[delegate sendDataToA:array];
}
}
-(void)giveValuestoNSmutableArray
{
array = [NSArray arrayWithObjects:#"Jill Valentine", #"Peter Griffin", #"Meg Griffin", #"Jack Lolwut",
#"Mike Roflcoptor", #"Cindy Woods", #"Jessica Windmill", #"Alexander The Great",
#"Sarah Peterson", #"Scott Scottland", #"Geoff Fanta", #"Amanda Pope", #"Michael Meyers",
#"Richard Biggus", #"Montey Python", #"Mike Wut", #"Fake Person", #"Chair",
nil];
}
detailcontroller.h
#import <UIKit/UIKit.h>
#import "Essentialinfocontroller.h"
#interface detailcontroller : UIViewController <sendTestData>
#end
detailcontroller.m
#import "detailcontroller.h"
#interface detailcontroller ()
#end
#implementation detailcontroller
- (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.
Essentialinfocontroller * acontollerobject=[[Essentialinfocontroller alloc] initWithNibName:#"Essentialinfocontroller" bundle:nil];
acontollerobject.delegate=self; // protocol listener
[self.navigationController pushViewController:acontollerobject animated:YES];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)sendDataToA:(NSArray *)array
{
for (NSString *string in array) {
NSLog(#"%#", string);
}
}
#end
You've got the relationship between controllers and delegates a little backwards. A delegate is used to pass information back. Your tableViewController is the detailController's delegate, and detailController shouldn't be allocating an EssentialInfoController inside it. You're basically creating a whole new EssentialInfoController that's different from the first one.
The easiest way to pass data is just to set it when the detailController is allocated. Also, since you're using storyboards, you have to use (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender to allocate the detailController.
Here's what I would do:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row==0){
[self performSegueWithIdentifier:#"OpenDetailsController"];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
DetailController *controller = (DetailController *)[segue destinationViewController];
NSArray *array = <your array here>;
[controller setArray:array];
}
In your storyboard, set the Storyboard Segue Identifier for that segue to "OpenDetailsController".
A delegate function is defined through a protocol, and you would have the DetailController call its delegate like this:
[self.delegate doSomething];
And in the EssentialInfoViewController you have to define the delegate function
-(void)doSomething {
}
I am trying to implement a car2go style app where you click on an annotation view and then can reserve the car. The problem is when I try to segue I want to pass the car object over, I check if the object performs the selector set vehicle but the if statement fails although I am pretty sure it is implemented. Can someone tell me why? This is for a school project.
#import "MapViewController.h"
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#import "Vehicles+Company.h"
#import "Vehicles+MKAnnotation.h"
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"reserveCar"]) {
if ([sender isKindOfClass:[MKAnnotationView class]]) {
MKAnnotationView *aView = sender;
if ([aView.annotation isKindOfClass:[Vehicles class]]) {
Vehicles *vehicle = aView.annotation;
if ([segue.destinationViewController respondsToSelector:#selector(setVehicle:)]) {
[segue.destinationViewController performSelector:#selector(setVehicle:) withObject:vehicle];
}
}
}
}
}
This is the viewcontroller it is segueing to.
.h file
#import <UIKit/UIKit.h>
#import "Vehicles+MKAnnotation.h"
#import "Vehicles.h"
#import "Vehicles+Company.h"
#interface CompanyVehicleViewController : UIViewController
#property (nonatomic,strong) Vehicles *vehicle;
#end
.m file
#import "CompanyVehicleViewController.h"
#interface CompanyVehicleViewController ()
#end
#implementation CompanyVehicleViewController
-(void) setVehicle:(Vehicles *)vehicle{
_vehicle = vehicle;
self.title = vehicle.name;
NSLog(#"Vehicle is %#", vehicle);
}
- (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.
}
#end
Most likely segue.destinationViewController isn't an instance of CompanyVehicleViewController.
Verify in your storyboard that the view controller's type is set to the proper class.
I'm writing a method that takes a string from a textfield, and sends it over to a cloudcode function on Parse's end. Xcode is giving me the error Use of undeclared identifier 'PFCloud', even though I've imported the parse header in SearchViewController.h. What could be causing this?
SearchViewController.m:
#import "SearchViewController.h"
#interface SearchViewController ()
#property (weak, nonatomic) IBOutlet UITextField *itemSearch;
#property (weak, nonatomic) IBOutlet UIButton *nextButton;
#end
#implementation SearchViewController
- (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.
}
- (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
{
if (sender != self.nextButton) return;
if (self.itemSearch.text.length > 0) {
[PFCloud callFunctionInBackground:#"averageStars"
withParameters:#{#"item": self.itemSearch.text}
block:^(NSNumber *ratings, NSError *error) {
if (!error) {
// ratings is 4.5
}
}];
}
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
#end
SearchViewController.h:
#import <UIKit/UIKit.h>
#import <Parse/Parse.h>
#interface SearchViewController : UIViewController
#end