Am trying to write a simple custom delegate for displaying multiple selection list (after referring various online tutorials, stackoverflow, Apple doc), but in the class that I want to use the delegate, the line where I set the delegate runs into an infinite loop when I run it.
I have shared the source code here
https://bitbucket.org/ikosmik/uilistviewcontroller/src/ddfcd140b52e6e59d84e58d34d601f8f850145a1/UIList?at=master
UIListViewController (where am declaring the protocols)
https://bitbucket.org/ikosmik/uilistviewcontroller/src/ddfcd140b52e6e59d84e58d34d601f8f850145a1/UIList/UIListViewController.h?at=master
And am trying to use the delegate in a UIViewController called View_Exporter
#import <UIKit/UIKit.h>
#import "UIListViewController.h"
#interface View_Exporter : UIViewController <UIListViewDelegate, UIListViewDataSource>
#property (nonatomic, strong) IBOutlet UIView *viewForList;
#property (nonatomic, strong) UIListViewController *listViewController;
#end
View_Exporter.m
#import "View_Exporter.h"
#implementation View_Exporter
#synthesize arraySelectedList;
#synthesize viewForList;
#synthesize listViewController;
#pragma mark - UIListViewController Methods
-(NSArray *) itemsForList {
NSLog(#"View_Exporter itemsForList");
NSArray *array = [NSArray arrayWithObjects:#"Server", #"Memory", nil];
return array;
}
- (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.
self.listViewController = [[UIListViewController alloc] initWithNibName:#"UIListViewController" bundle:nil];
self.listViewController.listViewDelegate = self;
//[self.viewForList addSubview:self.listViewController.view];
self.listViewController.listViewDataSource = self;
}
#end
But this line in viewDidLoad seems to loop infinitely when I run the code :
self.listViewController.listViewDelegate = self;
Why is this looping infinitely? Am breaking my head since yesterday on this. not sure where am going wrong. can someone please help?
You've written a custom setter for listViewDelegate, at the end of this method you do this:
self.listViewDelegate = delegate;
This just calls the setter method again. Accessing a property via self. is just a way of calling[self setXX:xxx]. In your accessor method you need to set the instance variable directly, in the normal case this would be just
_delegate = delegate;
(The _delegate instance variable is created for you automatically). You can safely remove all of your synthesize statements, they aren't needed any more.
Related
I have simple example:
NavViewController
ViewController
ViewController2
In ViewController:
#import "ViewController.h"
#import "ViewController2.h"
#interface ViewController ()
#end
NSArray *array;// Neither in #interface nor in #implementation
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
array = [[NSArray alloc] initWithObjects:#"12345", nil];
ViewController2 *vc = [[ViewController2 alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
In ViewConroller2:
#import "ViewController2.h"
#interface ViewController2 ()
#end
NSArray *array;
#implementation ViewController2
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%#",array);
}
I don't understand why my array in viewController2 passed data from viewController?
Can explain this?
Guys I know how pass data to another viewController with property. I want to understand why, in this case, the data is transferred!
Because you've declared NSArray *array; as a Global variable. And, as long as the variable is defined somewhere in a source file, the linker will be able to find it and appropriately link all the references in other source files to the definition.
we also declare global variables using extern
extern int GlobalVar;
Here, externtells the compiler that this is just a declaration that an object of type int identified by GlobalVar exists and linker's job to ensure.
In one of your source file, you could say
int GlobalVar = 7;
I believe this is the reason in your case.
When you declare your variable outside #interface or #implementation it is considered to be static variable hence it worked. keep it inside would not work.
#interface ViewController ()
{
NSArray *array;
}
#end
try this instead of your code
So I'm trying to get a hang of using delegates, and I've watched a few tutorials on how to use them so far. I still find them confusing and after trying to implement one myself, have an issue that I can't seem to solve.
I have two ViewControllers, the first one ViewController contains a UITextField *sampleTextField and a button with the method switchViews. It also contains the protocol declaration with the method sendTextToViewController. SwitchViews is also linked to a segue that switches to the SecondViewController. In SecondViewController the only object is a UILabel *outputLabel When the user taps the button, it calls switchViews and the view changes to SecondViewController, and upon loading outputLabel should be changed to whatever text was entered in sampleTextField in ViewController. However the delegate method sendTextToViewController is never being called. All objects are created in Interface Builder.
Here is the code to make it a bit easier to understand:
ViewController.h
#import <UIKit/UIKit.h>
#protocol TextDelegate <NSObject>
-(void)sendTextToViewController:(NSString *)stringText;
#end
#interface ViewController : UIViewController
- (IBAction)switchViews:(id)sender;
#property (weak, nonatomic) IBOutlet UITextField *sampleTextField;
#property (weak, nonatomic) id<TextDelegate>delegate;
#end
Then declared this in ViewController.m
- (IBAction)switchViews:(id)sender {
NSLog(#"%#", self.sampleTextField.text);
[self.delegate sendTextToViewController:self.sampleTextField.text];
}
SecondViewController.h
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface SecondViewController : UIViewController <TextDelegate>
#property (weak, nonatomic) IBOutlet UILabel *outputLabel;
#end
SecondViewController.m
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
#synthesize outputLabel;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
ViewController *vc = [[ViewController alloc]init];
[vc setDelegate:self];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)sendTextToViewController:(NSString *)stringText
{
NSLog(#"Sent text to vc");
[outputLabel setText:stringText];
}
I've looked at this and the first answer makes sense, but for some reason it's not working.
I do think that the problem is where I am setting calling [vc setDelegate:self], but not sure how to fix this. Some pointers in the right direction would be greatly appreciated. Keep in mind I'm new to obj-c so if you can explain what you are saying, that would be great. Thank you.
Your are creating a new instance of ViewController but you don't do anything with it.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
ViewController *vc = [[ViewController alloc]init];
[vc setDelegate:self];
}
The SecondViewController needs to have reference to the FirstViewController to be able to set itself as a delegate.
First you don't have to use delegation to do such a program.
A simpler way would be just creating a property in the SecondViewController that you'll pass the content of the textField into it.
Your code doesn't work because you called sendTextToViewController on a delegate that hasn't been set. You have set the delegate to a new instance of ViewController, not the one presented onscreen.
I'm trying to implement simgle AdBanner instance for multiple views in an iOS app. For implementing AdbannerDelegate in a viewController one has to do
bannerview.delegate= self;
where bannerview is an instance of AdBannerView. This delegate method however has to be implemented in every viewController which amounts up to a lot of repeating code. How can I make up a simple class that implements all delegate methods and then I call use them in every viewController.
I think the viewControllers you are using are subclasses of UIViewController.
And you are saying all the viewControllers have the same delegate methods.
So,what i want to do is create new ViewController class (UIDelgateViewController) by SubClassing UIViewController and add all delegate methods there , and have all the other viewControllers subclass UIDelgateViewController.
The code goes like this,
.h file->
#interface UIDelegateViewController : UIViewController<ADBannerViewDelegate>
#property ADBannerView *bannerView;
#end
.m file ->
#import "UIDelegateViewController.h"
#interface UIDelegateViewController ()
#end
#implementation UIDelegateViewController
- (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.
_bannerView = [[ADBannerView alloc] init];
_bannerView.delegate =self;
}
-(void)bannerDelegateMethod{
}
Now your Some viewController ->
#import "UIDelegateViewController.h"
#interface SomeViewController : UIDelegateViewController
#end
#import "SomeViewController.h"
#interface SomeViewController ()
#end
#implementation SomeViewController
- (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.
[self.view addSubview:self.bannerView];
self.bannerView.frame = ..../
}
If you want to keep always on the screen the same banner while navigating and changing views, you should consider to use View Controller containtment API
A great example is that remarkable sample code written by Apple, that shows how to keep the same banner instance while moving in a tabbar or navigation controller. It could be also a great start for you project.
I know how to call a method of one class to another class. However This time its not working for me and its just driving me nuts. Below is my code
MenuPageCell.h
#import <UIKit/UIKit.h>
#class MenuPageViewController;
#interface MenuPageCell : UITableViewCell{
NSInteger m_cellIndex;
MenuPageViewController *m_parentViewController;
}
#property(nonatomic, assign) NSInteger m_cellIndex;
#property(nonatomic, strong) MenuPageViewController *m_parentViewController;
-(IBAction) addToCart;
#end
MenuPAgeCell.m
#import "MenuPageCell.h"
#import "MenuPageViewController.h"
#implementation MenuPageCell
#synthesize m_cellIndex;
#synthesize m_parentViewController;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
-(IBAction) addToCart
{
NSLog(#"Add To cart = %d",self.m_cellIndex);
[m_parentViewController addItemToCart:self.m_cellIndex];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
MenuPageViewController.m
-(void) addItemToCart:(NSInteger)aIndexItem
{
NSLog(#"In Add to Cart method");
}
Now, This code works fine for non ARC Used project but its not working for me. I know it should be silly mistake but I'm unable to figure it out.
Thanks & regards
Mayur
Referencing ViewController from a cell is a design flaw, consider using delegate instead. But if you really need the ViewController property, make it weak instead of strong because currently you end up with retain cycle.
#protocol MenuPageCellDelegate<NSObject>
- (void)addItemToCart:(NSInteger)aIndexItem;
#end
#interface MenuPageCell : UITableViewCell {
NSInteger m_cellIndex;
}
#property(nonatomic, assign) NSInteger m_cellIndex;
#property(nonatomic, weak) id<MenuPageCellDelegate> delegate;
-(IBAction) addToCart;
#end
#implementation MenuPageCell
...
-(IBAction) addToCart
{
NSLog(#"Add To cart = %d",self.m_cellIndex);
if ([self.delegate responsToSelector:#selector(addItemToCart:)]) {
[self.delegate addItemToCart:self.m_cellIndex];
}
}
...
#end
Add MenuPageCellDelegate to the list of implemented protocols of MenuPageViewController and (if it's implementing UITableViewDataSource protocol) in the tableView:cellForRowAtIndexPath: method write cell.delegate = self; instead of cell.m_parentViewController = self;
initialize your m_parentViewController in viewDidLoad method.
such like
m_parentViewController = [[yourViewControllerName alloc] init];
and then call
[m_parentViewController addItemToCart:self.m_cellIndex];
in the cellforrow method of your tableview add a selector to the cell button and also set the tag equal to the indexpath. now in the selector just distinguish between the different cells with the help of sender.tag.
It works if I put it in viewDidLoad but I can't imagine that's the best place to do it. I tried putting it here:
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// HERE
}
return self;
}
But that didn't work. Where should I put it?
In this example I'm talking about creating the NSMutableArray (alloc and initing it) for this class.
You could go with a lazy-loading technique as A-Live suggests in the comments, such that your array will be initialized when you actually need it. The idea is that in a property getter, you first check to see if your array was initialized. If not, initialize then return it.
Example
Note: This is a crude and untested example, and you may need to make
the necessary changes depending on whether or not you use ARC.
MyViewController.h
#interface MyViewController : UITableViewController
{
NSArray *_myArray;
}
#property (nonatomic, readonly) NSArray *myArray;
-(void)doSomething;
#end
MyViewController.m
#interface MyViewController()
-(NSArray *)fetchArrayData;
#end
#implementation MyViewController
#synthesize myArray = _myArray;
#pragma mark - Property Getter
-(NSArray *)myArray
{
if (_myArray==nil)
_myArray = [[self fetchArrayData] retain];
return _myArray;
}
#pragma mark - Cleanup
-(void)dealloc
{
[_myArray release];
[super dealloc];
}
#pragma mark - Instance Methods
-(void)doSomething
{
NSLog(#"myArray: %#", self.myArray);
}
#pragma mark - Private Methods
-(NSArray *)fetchArrayData
{
NSArray *arrayData = [NSArray arrayWithObjects:#"Apples", #"Oranges", nil];
return arrayData;
}
#end
You have 4 initialization methods:
- (id)init
- (id)initWithCoder:(NSCoder *)aDecoder
- (id)initWithStyle:(UITableViewStyle)style
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
It all dependes on how you're instantiating the class.
You can initialize your instance variables in initWithStyle: if you create your controller programmaticaly or in initWithCoder:/awakeFromNib if it's loaded from nib/storyboard.