Objects in class are nil when trying to access from another class - ios

I have a View Controller class which contains a button property, and I need to change its enabled stated from a different class (Table View Controller). I'm also calling a method that's in that VC class. I can call the method just fine, but when I try to access the button property, it's nil. Actually all of its properties are nil. I must have something not set up quite right.
//ViewController.h
#property (strong, nonatomic) IBOutlet UIButton *aButton;
- (IBAction)myButtonTapped;
//ViewController.m
//did not override setter or getter for aButton
- (IBAction)myButtonTapped {
//code here
}
//Table VC.m
#property (strong, nonatomic) ViewController *myVC;
- (ViewController *)myVC {
if (!_myVC) _myVC = [[ViewController alloc] init];
return _myVC;
}
- (void)userEnteredText:(NSNotification *)notification {
[self.myVC myButtonTapped]; //runs method without issue
self.myVC.aButton.enabled = YES; //does not occur since aButton is nil - myVC is not nil
}

You need to study the information provided by #Hot Licks to understand how to keep references between your objects, but I can tell you that part of your problem is your getter method -
- (ViewController *)myVC {
if (!_myVC) _myVC = [[ViewController alloc] init]; // <-- This is a problem
return _myVC;
}
If your _myVC variable is nil then your getter method allocates a new ViewController - so you won't get a reference to the existing viewController. As you then call the plain init method for your new viewController none of its properties will be initialised - so you get nil for your button.
You don't need to write any code for a simple property like this - the default code that is created for you is all you need. What you do need to do is set the myVC property from your current viewController instance. So somewhere in your viewController you will have
tableVC.myVC=self;
You will need to do this somewhere where you have a reference to your tableVC - so this could be inprepareForSegue if you are using storyboards and segues or wherever you present or push the table vc if you aren't

Related

Delegate not working in iOS

I feel frustrated with this problem, I my delegate doesn't work, Here's the code snippet below. I'm just using xib in this application.
//classA.h file
ClassA.h
#import "ClassB.h"
#interface ClassA : UIViewController< ClassBDelegate >
//classA.m file
**ClassA.m**
-(void)didSuccessPreview:(ClassB *)controller andLog:(NSString *)log{
NSLog(#"%#", log);
}
//classB.h file
**ClassB.h**
#import <UIKit/UIKit.h>
#class ClassB;
#protocol ClassBDelegate <NSObject>
- (void)didSuccessPreview:(ClassB *)controller andLog:(NSString *)log;
#end
#interface ClassB : UIViewController
#property (weak, nonatomic) id< ClassBDelegate >delegate;
//classB.m file
**ClassB.m**
I add this code below inside view did load
[self.delegate didSuccessPreview:self andLog:#"zz"];
I have other delegate inside my application same as the code above, but it works but this one is not, I don't know why. Inside my classA I have a button then when i click it it goes to classB, then when it goes to viewdidload in ClassB, the delegate doesn't fired.
Depending on where you assign the delegate, your code might need to look like this:
ClassB viewController = [ClassB new];
ClassA delegateStrongRef = [ClassA new]
viewController.delegate = delegateStrongRef; // <-- you are missing this now;
// Fixed: the ClassA object must be referenced strongly somewhere else
// besides the (weak)delegate property, otherwise it will be deallocated.
(The code above is the part where you create the instance of ClassB, the view controller. It might be inside the AppDelegate, another viewController's implementation, anything - depending on how your app is structured).
Then, in the view controller's -viewDidload method, you can have the delegate execute a method like this:
- (void)viewDidLoad
{
[self.delegate didSuccessPreview:self andLog:#"zz"];
}
so, at some point after instantiating your view controller, you need to assign an object of type ClassA (the class that adopts the delegate protocol) to its delegate property, otherwise it will be nil and any messages sent to it will be ignored (no method executed).
Properties and instance variables of object type are not allocated automatically, but initialized to nil (ints, floats etc, are initialized to 0, 0.0f, etc.)
EDIT: If you are assigning the delegate from ClassA's code, then it might look like this:
ClassA.m:
- (void) someMethodOfClassA
{
ClassB viewController = [ClassB new];
viewController.delegate = self;
// e.g., Do something with the view controller...
[navigationController pushViewController:viewController animated:YES];
}
Since the delegate property is defined as a weak reference, before calling any method of the delegate make sure it has not been deallocated and its reference set back to nil (use NSLog or set a breakpoint).

passing data value between two view controller using custom protocol

1) I Am passing the value between two view controller using custom
protocol..But the value always showing NULL.
I need to pass the value from second view controller to first view controller
2) In Secondview controller.h
#protocol PopoverTableViewControllerDelegate <NSObject>
#property (nonatomic, strong) id<PopoverTableViewControllerDelegate>myDelegate;
3) secondview controller.m
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary*dict=[sercharray objectAtIndex:index];
str=[dict objectForKey:#"id"];
NSLog(#"test value %#",str);
[self.myDelegate didSelectRow:str];
NSLog(#"delegate value %#",self.myDelegate);
//THIS VALUE ALWAYS SHOWING NULL AND ALSO I SHOULD PASS THIS VALUE TO FIRST VIEW
CONTROLLER.I SHOULD USE DISMISS VIEW CONTROLLER.
[self dismissViewControllerAnimated:YES completion:nil];
}
4) First View controller.h
#interface Firstviewcontroller :
UIViewController<PopoverTableViewControllerDelegate>
5) First view controller.m
secondviewcontroller *next=[[seconviewcontroller alloc]init];
next.myDelegate=self;
(void)didSelectRow:(NSString *)cellDataString {
passstring = cellDataString;
NSLog(#"pass string %#",pass string);
//first view controller str variable value i need to pass this string[passstring].
}
I think you might be a little confused about what Delegation is used for and why. For example you might want to make a protocol in a UIViewController subclass if you were doing some kind of action in that ViewController and needed to inform another subclass that that action is being taken, or of the result of that action. Now in order for the subclass that wants to know about the action(the receiver), it has to conform to that protocol in it's header file. You also must "set" the delegate to the receiving class/controller. There are many ways to get a reference to the receiving controller/class to set it as the delegate but a common mistake is allocating and initializing a new instance of that class to set it as the delegate, when that class has already been created.What that does is set your newly created class as the delegate instead of the class that's already been created and waiting for a message. What your trying to do is just pass a value to a Newly created class. Since your just creating this UIViewController class all thats needed for that is a Property in the receiver(ViewControllerTwo). In your case a NSString:
#Property (nonatiomic, retain) NSString *string; //goes in ViewControllerTwo.h
and of course don't forget in the main:
#synthesize string; //Goes in ViewControllerTwo.m
Now there is no need for a setter in your ViewControllerTwo.
- (void)setString:(NSString *)str //This Method can be erased
{ //The setter is created for free
self.myString = str; // when you synthesized the property
}
The setter and Getters are free when you use the #synthesize. Just Pass the value over to the ViewController. The implementation is identical to your code except for the delegate:
ViewControllerTwo *two = [[ViewControllerTwo alloc] initWithNibName:#"ViewControllerTwo" bundle:nil];
[two setString:theString];
[self.navigationController pushViewController:two animated:YES];
[two release];

Modifying UIButton's alpha property from another class

I'm trying to change the alpha of an UIButton from another class. The function that is called in set the alpha property of my UIButton is actually called because I've put a NSLog there and I can see how it works. I'd be thankful if you could give me any suggestion.
Here's my current code.
ViewController.h
- (void) setAlphaToButton;
#property (strong, nonatomic) IBOutlet UIButton *myButton;
ViewController.m
#synthesize myButton;
- (void) setAlphaToButton {
myButton.alpha = 0.5;
NSLog(#"Alpha set");
}
ImageViewSubclass.m
- (void) tapDetected:(UITapGestureRecognizer *)tapRecognizer {
ViewController *VC = [[ViewController alloc] init];
[VC setAlphaToButton];
}
And when the image view is pressed, in my console I get: Alpha set. And the button doesn't change.
In your code, an instance of ViewController is alloced and inited, and the method setAlphaToButton is called on it. Then the view controller is released because you have no object retaining it. That's why you don't see any effect; the ViewController instance you call the method on never appears on screen.
It's not clear how your code is supposed to work; do you have an instance of ViewController in existence when tapDetected is called? If this is the case, and this is the ViewController whose button you want to alter the alpha of, then you need to have a reference to that instance of ViewController and call setAlphaToButton on it.
Your view is not loaded at the moment you trying to set alpha! You need to call this method after your viewDidLoad fired. You can force it by calling view, but it's kind of hackand not recommended!
MyViewController *vc = [MyViewController new];
vc.view; // this string will force view loading
[vc setAlphaToButton];
Add a property of uiviewcontroller class in imageviewsubclass as
ImageViewSubclass.h
#propery (nonatomic, retain) uiviewController *parent;
ImageViewSubclass.m
#synthesize parent;
And initialize it with "self" in view controller class when initalize object of imageviewsubclass and add on the view like
ImageViewsubclass *oneObj = [ImageViewsubClass alloc] init];
oneOBj.parent = self;
do the same for all objects of ImageviewsubClass objects.
and in
- (void) tapDetected:(UITapGestureRecognizer *)tapRecognizer {
[parent setAlphaToButton];
}

Unable to set custom protocol delegate using ARC with two UITableViewControllers using UINavigationController

I'm trying to set the delegate for my custom protocol that has one required method allowing me to pass an array of objects back in the hierarchy of two UITableViewControllers. My delegate continues to return nil. Due to this, my required method is never called.
I'm wondering if the datasource and delegate implementations with my UITableViewControllers is causing a conflict. Also, perhaps ARC is getting in the way when declaring the delegate?
It should be noted that both UITableViewControllers were built using Storyboard and are navigated using segues within a UINavigationController (not sure if this may be causing issues or not).
The nav is --> AlarmViewController --> AlarmDetailsViewController. I create an Alarm object in my AlarmDetailsViewController that contains all the details for an alarm, place it into an array and I want to pass that array back to my AlarmViewController to be displayed in a custom cell in the table.
NOTE: I want to use the Delegate pattern here. I'm not interested in solutions that invoke NSNotifications or use my AppDelegate class.
AlarmDetailsViewController.h
#import "Alarm.h"
#protocol PassAlarmArray <NSObject>
#required
-(void) passAlarmsArray:(NSMutableArray *)theAlarmsArray;
#end
#interface AlarmDetailsViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate>
{
//.....
id <PassAlarmArray> passAlarmsArrayDelegate;
}
#property (nonatomic, retain) id <PassAlarmArray> passAlarmsArrayDelegate;
#end
AlarmDetailsViewController.m
#import "AlarmDetailsViewController.h"
#interface AlarmDetailsViewController ()
#end
#implementation AlarmDetailsViewController
#synthesize passAlarmsArrayDelegate;
-(void) viewWillDisappear:(BOOL)animated
{
NSLog(#"delegate = %#", self.passAlarmsArrayDelegate); // This prints nil
[[self passAlarmsArrayDelegate] passAlarmsArray:alarmsArray];
}
//....
#end
AlarmViewController.h
#interface AlarmViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate, PassAlarmArray>
{
//...
AlarmDetailsViewController *alarmDetailsViewController;
}
#property (nonatomic, retain) AlarmDetailsViewController *alarmDetailsViewController;
#end
AlarmViewController.m
#import "AlarmViewController.h"
#import "AlarmDetailsViewController.h"
#import "AlarmTableViewCell.h"
#import "Alarm.h"
#interface AlarmViewController ()
#end
#implementation AlarmViewController
#synthesize alarmDetailsViewController;
- (void)viewDidLoad
{
[super viewDidLoad];
// This is where I'm attempting to set the delegate
alarmDetailsViewController = [[AlarmDetailsViewController alloc]init];
[alarmDetailsViewController setPassAlarmsArrayDelegate:self];
}
//....
//My #required protocol method which never gets called since my delegate is nil
-(void) passAlarmsArray:(NSMutableArray *)theAlarmsArray
{
alarmsTableArray = theAlarmsArray;
NSLog(#"alarmsTableArray contains: %#", alarmsTableArray); // Never gets called due to delegate being nil
NSLog(#"theAlarmsArray contains: %#", theAlarmsArray); // Never gets called due to delegate being nil
}
#end
I've attempted to set the delegate in a method that fires when a button is pressed in AlarmViewController (as opposed to the viewDidLoad method) but that does not work either.
I'm assuming I've got a logic flow error somewhere here . . . but nearly 2 days of hunting and rebuilds haven't uncovered it. Ugh.
You're setting your delegate in the wrong place, and on a different instance of the controller than the one you will get when you do the segue. You should set the delegate in the prepareForSegue method if you're pushing AlarmDetailsViewController from AlarmViewController
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
AlarmDetailsViewController *alarm = segue.destinationViewController;
alarm.passAlarmsArrayDelegate = self;
}
You really need to understand the life cycle of view controllers, how and when they're instantiated, and when they go away. This is the very heart of iOS programming, and Apple has extensive documentation on it. Reading up on segues would also be very useful. A segue (other then an unwind segue) always instantiates a new instance of the destination controller. So, when your segue is performed, whether directly from a button, or in code, a new (different from the one you alloc init'd directly) details controller is instantiated. Before that segue is performed, prepareForSegue: is called, and that's when you have access to the one about to be created. That's the place to set a delegate or pass any information on to the destination view controller.
Did you try replace (nonatomic, retain) with (nonatomic, strong) since you are using ARC?
Auto-synthesized properties like your alarmDetailsViewController property have backing ivars prefixed with underscores, e.g. _alarmDetailsViewController. Your alarmDetailsViewController ivar (the alarmDetailsViewController declared inside the #interface ... {} block in AlarmViewController.h) is different from the backing ivar of your alarmDetailsViewController property.
Just delete your alarmDetailsViewController ivar and use the #property, preferably through self.alarmDetailsViewController.

Using my own delegate

I´m having problems declarating my own delegate. Well...thats not exactly true: i have it declarated and, when i build the project, the compiler reports no issues. I declarated it in this way:
I made a file (enviarDatos.h) for declare the protocol:
#protocol enviarDatos <NSObject>
- (void)addItemViewController:(NSMutableArray *)item;
#end
In the Vista2.h (ViewController) file I imported the file enviarDatos.h and declared a property:
#property (nonatomic, weak) id <enviarDatos> delegare;
In the Vista2.m (ViewController) file I use the protocol method:
#interface ViewController : UIViewController <enviarDatos> {
And, finally, in the ViewController.m file I implement the delegates method:
- (void)addItemViewController:(NSMutableArray *)ar {
origen = ar;
}
Does anyone see something wrong? the code of the last function its never executing.
Thanks for your help.
EDIT:
What i need is to change an array in ViewController from Vista2 (another viewcontroller)
Then create delegate property in next view(child view) & set it to self in parent view while pushing or showing child view.
ParentView.m
1.Implement protocol methods
- (void)addItemViewController:(NSMutableArray *)ar
{
origen = ar;
}
2.While showing child view
ChildViewController *child = [[ChildViewController alloc] init];
child.delegate = self;
//present child view
ChildView.h
#property (nonatomic, weak) id <enviarDatos> delegare;
ChildView.m
-(void) anyMethod
{
if([self.delegate respondsToSelector:#selector(addItemViewController:)])
{
[self.delegate addItemViewController:mutableArray];
}
}
Ah, it looks like you are declaring the delegate property in the wrong place.
You should declare the property delegate in enviarDatos.h.
#property (nonatomic, weak) id <enviarDatos> delegate;
Then in Vista2.m you will do something like this...
EnviarDatos *myObject = [[EnviarDatos alloc] init];
myObject.delegate = self;
This then sets up the EnviarDatos object and assigns the Vista2 object as the delegate.
Now, in EnviarDatos.m you can run...
[self.delegate addItemViewController:someObjectArray];
And this will then run that code in the Vista2 object.
Delegates are used for calling back to objects that create them (or some other objects). If you create an object and then want to run a method in it then you won't need a delegate.
Can you say at what condition addItemViewController is invoked?
You seem to be on the right track, but are you sure you are setting the delegate as
[yourObject setDelegate: self];
Have you tried debugging it? Does the debugger pause at addItemViewController if you set a breakpoint there? Can you confirm the delegate is not null inside the method? I may post some code but your seems to be right except for the assigning of delegate, I think you should check it.

Resources