iOS - delegate not working - ios

i have two view controllers, AbcViewController and XyzViewController. Both controllers behave similarly. Each has a "add" button which opens up a AddNewAbcViewController and AddNewXyzViewController respectively.
On AddNewAbcViewController, when the button "submit" is taped, it does it necessary stuff and close, bringing it back to AbcViewController. I am using delegate here where AbcViewController does the closing of AddNewAbcViewController. This works.
Now I want to do the same for XyzViewController and AddNewXyzViewController, but it is not working. When the btnSubmit is called in AddNewXyzViewController, it didn't enter into XyzViewController dimiss method. I have scanned through my codes many times but don't find anything extra not added. I even gave a different dismiss method name in XyzViewController and AddNewXyzViewController but that didn't work either. What did I miss?
here are my snippets for AbcViewController and AddAbcViewController. The codes for Xyz are identical:
class AddNewAbcViewController.h is
#import <Foundation/Foundation.h>
// protocol
#protocol AddNewAbcProtocol <NSObject>
-(void)dismiss;
#end
#interface AddNewAbcViewController : UIViewController<UITextViewDelegate>
#property(nonatomic, weak)id<AddNewAbcProtocol> delegate;
#end
class AddNewAbcViewController.m is
#interface AddNewAbcViewController() <UINavigationControllerDelegate, UIImagePickerControllerDelegate>
...
#end
#implementation AddNewAbcViewController
...
- (IBAction)btnSubmit:(id)sender
{
[self.delegate dismiss];
}
#end
class AbcViewController.h is
#import <Foundation/Foundation.h>
#import "AddNewAbcViewController.h"
#interface AbcViewController : UIViewController<AddNewAbcProtocol, UISplitViewControllerDelegate>
...
#end
class AbcViewController.m is
#implementation AbcViewController
-(void)dismiss
{
NSLog(#"delegated to dismiss()");
[self dismissViewControllerAnimated:YES completion:nil];
}
#end

As everyone explained, basically you forgot a line of code like ".delegate = self".
Here's a handy beginner's intro to delegates.
https://stackoverflow.com/a/4213005/294884

Use if statement to see if delegate works:
if ([self.delegate respondsToSelector:#selector(dismiss)])
{
[self.delegate dismiss];
}
Create AddNewXyzViewController as an instance variable, but not a local variable.

Related

Warning "Method definition not found" in Objective-C. Call Method from Category file

I have created some method in category file. I just want to reuse those methods in my view controllers. So I have imported that category file in view controllers and declared the method in header file also.
calling it like this:
Category class:
#interface UIViewController (headerView)
-(UILabel *)someMethod;
#implementation UIViewController (headerView)
-(UILabel *)someMethod{
}
HomeViewController:
#interface HomeViewController : UIViewController
-(UILabel *)someMethod;
#implementation HomeViewController
[self someMethod];
I am getting warning message in this line:
#implementation HomeViewController
It's working. But I want to clear this warning. How can I do it?
If you want you category in view controller do it something like that
Your category
#interface UIViewController (ExtendedMethods)
- (void)someMethod;
#end
#implementation UIViewController (ExtendedMethods)
- (void)someMethod {
NSLog(#"Some method");
}
#end
MyViewController.m
#import "MyViewController.h"
#import "UIViewController+ExtendedMethods.h"
#implementation MyViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self someMethod];
}
#end

Pass Data between two view controllers using 'Delegation' : Objective-C

I am implementing an library(.a), and I want to send notification count from library to app so they can show in their UI, notification count. I want them to implement the only method like,
-(void)updateCount:(int)count{
NSLog(#"count *d", count);
}
How can I send the count from my library continuously so they can use it in updateCount method to show.
I searched and come to know about call back functions. I have no idea how to implement them. Is there any other way to do this.
You have 3 options
Delegate
Notification
Block,also known callback
I think what you want is Delegate
Assume you have this file as lib
TestLib.h
#import <Foundation/Foundation.h>
#protocol TestLibDelegate<NSObject>
-(void)updateCount:(int)count;
#end
#interface TestLib : NSObject
#property(weak,nonatomic)id<TestLibDelegate> delegate;
-(void)startUpdatingCount;
#end
TestLib.m
#import "TestLib.h"
#implementation TestLib
-(void)startUpdatingCount{
int count = 0;//Create count
if ([self.delegate respondsToSelector:#selector(updateCount:)]) {
[self.delegate updateCount:count];
}
}
#end
Then in the class you want to use
#import "ViewController.h"
#import "TestLib.h"
#interface ViewController ()<TestLibDelegate>
#property (strong,nonatomic)TestLib * lib;
#end
#implementation ViewController
-(void)viewDidLoad{
self.lib = [[TestLib alloc] init];
self.lib.delegate = self;
[self.lib startUpdatingCount];
}
-(void)updateCount:(int)count{
NSLog(#"%d",count);
}
#end

Passing data between UIViewController and UITableViewController not connected via segue

I followed the advice at this link Changing the value of a property of another UIViewController
I have a Login page that is connected to a github project that I downloaded called SWRevealViewController. It essentially provides a slide out menu for the application. I need to pass a value from my Login Page to the initial Page that is loaded with the SWRevealViewController. Can't seem to get it working. Can anyone point me in the right direction? What I have tried is the following:
LoginViewController.m
#import "LoginViewController.h"
#import "ProfileTableViewController.h"
#interface LoginViewController ()
#property (strong, nonatomic) ProfileTableViewController *secondViewController;
#end
#implementation dbViewController
-(id)init
{
if (self = [super init]) {
self.secondViewController = [[ProfileTableViewController alloc] init];
}
return self;
}
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender{
if([identifier isEqualToString:#"Login"]){
[self login:sender];
self.secondViewController.idNumber = _IDNumber;
_secondViewController.idNumber = _IDNumber;
return YES;
}
}
LoginViewController.h
#import <UIKit/UIKit.h>
#import <sqlite3.h>
#import "ProfileTableViewController.h"
#interface LoginViewController : UIViewController
#property (strong, nonatomic)NSString *IDNumber;
#end
ProfileTableViewController.h
#import <CoreLocation/CoreLocation.h>
#import <UIKit/UIKit.h>
#import <sqlite3.h>
#interface ProfileTableViewController : UIViewController <CLLocationManagerDelegate, UITextFieldDelegate>
#property (nonatomic) NSString *idNumber;
#end
ProfileTableViewController.m
#import "ProfileTableViewController.h"
#import "SWRevealViewController.h"
#import "ProfileEditFieldController.h"
#interface ProfileTableViewController ()
#end
#implementation ProfileTableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(_idNumber);
}
#end
Just to add clarification, the two blue controllers are the Login, and the three controllers on the right, one of them is the controller I would like to pass the value for
You should do it like this instead:
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
ProfileTableViewController *pvc = (ProfileTableViewController*)[segue destinationViewController];
pvc.idNumber = _IDNumber
}
Hope that works! :)
UPDATE:
I think what you need is NSUserDefaults, use it, and store the ID. You gonna need it in more than one controller I believe, and its easy to store data on.
NSUserDefaults
It's not 100% clear from what you've shown but I'm assuming that these view controllers are defined in a storyboard and that the "Login" segue is also defined in the storyboard and causes a transition from LoginViewController to ProfileTableViewController.
One thing I am confused about is why the #implementation line in LoginViewController.m says "dbViewController" but I'm assuming that's a typo and that it should be "#implementation LoginViewController".
So, assuming all of that is true, there are a couple of problems in your code. First, you shouldn't be creating the ProfileTableViewController in LoginViewController's init method. iOS will automatically alloc and init the ProfileTableViewController when the segue is performed.
Second, instead of using shouldPerformSegueWithIdentifier:sender:, you want to use prepareForSegue:sender:. When that method is called, iOS will have already created the ProfileTableViewController and you can set your property.
So, what you want is something like:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"Login"])
{
ProfileTableViewController * viewController = segue.destinationViewController;
viewController.idNumber = _IDNumber;
}
}

Why isn't my delegate object responding to method calls?

I ultimately want to write an iOS app incorporating ALAssetsLibrary, but as a first step toward understanding delegation, I'm trying to pass a simple message between two view controllers. For some reason, I can't seem to get the message to pass. In particular, the delegate object (derpy) doesn't appear to exist (if(self.derpy) returns NO)).
I asked the same question on the Apple forums and was told that I should be using segues and setting properties / calling methods using self.child instead, but that seems strange. If I were to pass messages using the parent / child properties, would I still be able to create my views in Interface Builder? Once I have my two views set up, say inside a UINavigationController, I'm not sure how to actually "wire them up" so I can pass messages between them. Sorry if the question is overly broad.
Here's the controller I'm declaring the protocol in (called PickerViewController):
Interface:
#import <UIKit/UIKit.h>
#import <AssetsLibrary/AssetsLibrary.h>
#protocol DerpDelegate <NSObject>
#required
- (void) test;
#end
#interface PickerViewController : UIViewController
#property (nonatomic, assign) id<DerpDelegate> derpy;
#end
Implementation:
#import "PickerViewController.h"
#interface PickerViewController ()
#end
#implementation PickerViewController
- (void)viewDidLoad
{
[super viewDidLoad];
if (self.derpy) { // If the delegate object exists
[self.derpy test]; // send it this message
} else {
NSLog(#"Still not working."); // This always returns (i.e., self.derpy doesn't exist)
}
}
Delegate controller (MainViewController) interface:
#import <UIKit/UIKit.h>
#import "PickerViewController.h"
#interface MainViewController : UIViewController <DerpDelegate> // public promise to implement delegate methods
#property (strong, nonatomic) PickerViewController *picker;
- (void) test;
#end
And lastly, the delegate controller (MainViewController) implementation:
#import "MainViewController.h"
#import "PickerViewController.h"
#interface MainViewController ()
#end
#implementation MainViewController
// Here's that method I promised I'd implement
- (void) test{
NSLog(#"Test worked."); // This never gets called
}
- (void)viewDidLoad {
[super viewDidLoad];
self.picker.derpy = self;
//lazy instantiation
- (PickerViewController *) picker{
if(!_picker) _picker = [[PickerViewController alloc]init];
return _picker;
}
EDIT: Many thanks to rydgaze for pointing me in the right direction with self.picker.derpy = self, but for some reason, things still aren't working properly. Importantly, once that property has been set, if(self.picker.derpy) returns YES from MainViewController. But if(self.derpy) is still returning NO when called from inside the PickerViewController's viewDidLoad. How can the property exist and not exist at the same time?
You need to be sure that you're setting the delegate on the instance of the view controller that you put on screen. If you're using a navigation controller and segues to go between MainViewController and PickerViewController, then you should set the delegate in prepareForSegue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
self.picker = (PickerViewController *)segue.destinationViewController;
self.picker.derpy = self;
}
You need to populate the delegate first.
Basically, your MainViewController shoudl at somepoint do a
picker.derpy = self;
Then when the delegate fires in PickerViewController, the callback will happen.
Edit:
A good practice is to do something like in PickerViewController
#property (nonatomic, assign) id<DerpDelegate > derpy;
and in your MainViewController indicate that you will implement the delegate
#interface MainViewController : UIViewController<DerpDelegate>
Eventually in your implementation of MainViewController
You will have something like
picker = [[PickerViewController alloc]init];
picker.derpy = self;
[picker doYourThing];
Once picker is all done, it may want to return results using the delegate.

Unable to pass value back to parentViewController

I have masterViewController and detailViewController. Masterview pushes detailView. When going back to masteViewController I want to update the foo value. But I only get NULL from nslog. How can I set the parenteViewContrller.foo value to #"bar" when navigationback?
masterViewController.h
NSString *foo;
-(void)setFoo:(NSString *)fooValue
#property(nonatomic, retain) NSString *foo;
masterViewController.m
#synthesize foo;
-(void)setFoo:(NSString *)fooValue{
NSLog(#"updated foo:%#", fooValue);
}
detailViewController.m
-(void)goBack{
[self.navigationController.parentViewController setValue:#"bar" forKey:#"foo"];
[self.navigationController popViewControllerAnimated:YES];
}
[UIViewController parentViewController] will not return what you are expecting from iOS 5 onward, instead you should be using [UIViewController presentingViewController]
If you are just targeting iOS 5, it is easy enough to start using presentingViewController instead, but if not I would advise that you manually pass your UIViewController on:
// DetailViewController.h
#class MasterViewController;
#interface DetailViewController : UIViewController
#property (assign, nonatomic) MasterViewController *masterViewController;
#end
// DetailViewController.m
#import "DetailViewController.h"
#import "MasterViewController.h"
#implementation DetailViewController
- (void)goBack {
[self.masterViewController setFoo:#"bar"];
// dismiss this view controller
}
#end
// MasterViewController.h
#interface MasterViewController : UIViewController
- (void)setFoo:(NSString *)bar;
#end
// MasterViewController.m
#import "MasterViewController.h"
#import "DetailViewController.h"
#implementation MasterViewController
- (void)goForward {
DetailViewController *detailViewController = ...;
[detailViewController setMasterViewController:self];
// present this view controller
}
#end
In order for setValue:ForKey: to work, your view controller must conform to NSKeyValueCoding protocol.
Try this:
-(void)goBack{
[self.navigationController.parentViewController setFoo:#"bar"];
[self.navigationController popViewControllerAnimated:YES];
}
and don't forget to retain/release appropriately in your setFoo: method. You probably also need to type cast parentViewController to avoid any warnings.
Pass the reference of the master with assign property to detail view.
Using this reference set the foo value before performing pop action.
gIf you want to pass a object to the parent you could try creating an external object in a header file and importing the header in the controller where you want to use it however THIS IS NOT BEST PRACTICE but it's a quick fix
import
extern MyObject* Object;
#interface GlobalVariables : NSObject {
}
#end
All you have to do now is include the header in the controllers and use the global variable.
If you want to do it by the books i suggest you create a delegate that handles the object passing.
Normally, under this scenario, you need to use delegate. Check out my answer to this similar question in this SO.

Resources