How to in a viewClass notify another View class - iphone

My first view PageView.m like this
PageView.m
albumListView = [[AlbumListView alloc] initWithFrame:CGRectMake(0, 0, 45, 480)];
albumListView.tag = 1001;
[self addSubview:albumListView];
albumListView.hidden = YES;
[albumView release];
I want when my CameraView moved set albumListView.hidden = NO.
How to do it!
CameraView.m
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
}
How to use delegate or other ways?
Thank you!

Assuming that PageView class is where the CameraView instance is created, you can do sthg like this:
In your CameraView class, define a protocol like this:
#class CameraView;
#protocol CameraViewDelegate <NSObject>
#optional
- (void)cameraViewMoved:(CameraView *)view;
#end
Then, in the same class implement a property to hold your delegate:
#property (nonatomic, assign) id<CameraViewDelegate> delegate;
In your CameraView implementation file, call your delegate's cameraViewMoved method when you want to notify it, like this:
if ([self.delegate respondsToSelector:#selector(cameraViewMoved:)]) {
[self.delegate cameraViewMoved:self];
}
Make your PageView class a delegate of your CameraView, by putting sthg like this in your PageView.h file:
#interface PageView : <CameraViewDelegate>
And in PageView.m class, first set yourself as the delegate of your cameraView by doing sthg like cameraView.delegate = self;
Then, implement the protocol method cameraViewMoved. Inside this method, you can do what you need.

Related

Delegates in iOS

I am a newbie to iOS world, so please ignore the obvious.
I am pushing a viewController(HelpViewController) on top of another viewController(MainViewController). When a particular action happens in the HelpViewController, I would like to update a variable inside the MainViewController. I understand for this I need to use delegate.
Here is my delegate header...
#protocol ViewControllerDelegate <NSObject>
#required
- (void) switchToggled:(BOOL)status;
#end
// Protocol Definition ends here
#interface ViewDelegate : NSObject
{
// Delegate to respond back
id <ViewControllerDelegate> _delegate;
}
#property (nonatomic,strong) id delegate;
-(void)sendMessage:(BOOL)status; // Instance method
#end
and implementation...
#implementation ViewDelegate
#synthesize delegate;
-(id)init {
self = [super init];
return self;
}
-(void)sendMessage:(BOOL)status
{
[delegate switchToggled:status];
}
- (void)dealloc
{
[super dealloc];
}
#end
So Now If I want to implement Protocol ViewControllerDelegate I need to specify in MainViewController, which I do as follows --
MainViewController <ViewControllerDelegate>
and
#pragma mark - ViewControllerDelegate delegate
-(void)switchToggled:(BOOL)status{
NSLog(#"Switch Toggled(%d) Message passed to MainViewController",status);
}
My question is how do I specify Object, which delegate property needs to point to, so that it can come back to MainViewController's "switchToggled".
One way I do is by having property inside HelpViewController as follows -
MainViewController.m
HelpViewController *helpVC = [[HelpViewController alloc] init];
helpVC.mainView = self;
[self.navigationController pushViewController:helpVC animated:YES];
[helpVC release];
HelpViewController.h
#property (nonatomic) MainViewController *mainView;
HelpViewController.m
#synthesize mainView;
ViewDelegate *myDelegate = [[ViewDelegate alloc] init];
// assign delegate
myDelegate.delegate = mainView;
[myDelegate sendMessage];
[myDelegate release];
Is this correct way to implement or there is better way to achieve this or am I totally wrong.
Thanks
You should do:
// HelpViewController.h
#protocol HelpDelegate
- (void)switchToggled:(BOOL)status;
#end
// HelpViewController.m
#interface HelpViewController : UIViewController
#property (nonatomic, assign) id<HelpDelegate> delegate;
- (id)initWithDelegate:(id<HelpDelegate>)delegate
#end
#implementation HelpViewController
- (id)initWithDelegate:(id<HelpDelegate>)delegate
{
if (self = [super init])
{
self.delegate = delegate;
}
}
- (void)sendMessage:(BOOL)status
{
[self.delegate switchToggled:status];
}
// MainViewController.h
#import "HelpViewController.h"
#interface MainViewController.h : UIViewController <HelpDelegate>
// MainViewController.m
- (void)someMethod
{
HelpViewController* viewController;
viewController = [HelpViewController alloc] initWithDelegate:self];
...
}
#pragma mark - Help Delegate
- (void)switchToggled:(BOOL)status
{
...
}
Give the delegate a name that makes clear to which class it belongs.
You don't need the extra class/files for ViewDelegate/ViewControllerDelegate. Just define the delegate in header of class it belongs to: HelpViewController.n in this case.
Similar: Implement the delegate method switchToggled: in the real class MainViewController, and not in the extra/unnecessary class ViewDelegate.
The purpose of delegates is to avoid class dependencies. By including MainViewController in HelpViewController you create such a dependency. This is not necessary as I show, and is wrong design.
You were also creating a circular dependency, because MainViewController already needed HelpViewController in order to show it, and now they need each other the other way around for sending the event.
Alternatively you can make HelpViewController's delegate public, have an init without argument, and expect users to set it with helpViewController.delegate = self; or something. But this would only make sense when the delegate being set is optional (which don't seems the case here, so adding it to the init method is appropriate).
I tell you what I would have done:
1) the protocol definition is ok, but do NOT create the class ViewDelegate, so:
//ViewControllerDelegate.h
#protocol ViewControllerDelegate <NSObject>
#required
- (void) switchToggled:(BOOL)status;
#end
2) Your implementation of the delegate method in MainViewController is ok.
3) Now... the important point:
//interface
#interface HelpViewController : UIViewController //or whatever superclass..
{
id <ViewControllerDelegate> _delegate;
}
#property (nonatomic,strong) id<ViewControllerDelegate> delegate;
#end
//implementation
#implementation HelpViewController
- (void)someMethodWhichCallsTheDelegate
{
//do something
...
// call delegate
//if switchToggled: were optional then add the following
//if ([self.delegate respondToSelector:#selector(switchToggled:)]) {
[self.delegate switchToggled:status];
}
#end
4) Now you have to assign the delegate:
//MainViewController.m
HelpViewController *helpVC = [[HelpViewController alloc] init];
helpVC.delegate = self;
[self.navigationController pushViewController:helpVC animated:YES];
[helpVC release];
And that's it!
BTW: if this delegate is related only to HelpViewControllerthen add the protocol definition where you define the interface of the class, it is not necessary to create a separate header file. If instead the protocol is "global", then it can have some sense to declare it separately.

event delegation

I have two uiviewcontroller: MainViewController and SecondaryViewControlle. In MainViewController I do:
[self.view addSubView:SecondaryViewControlle.view];
The SecondaryViewController is a button by pressing the function to be performed by a MainViewController. How to do?
You'd start by defining a protocol in your SecondViewControlle.h file, something like:
#protocol SecondViewControlleDelegate
- (void) doSomething
#end
You would also need to add a "delegate" ivar to your SecondViewControlle .h file. It would be the delegate line:
#interface SecondViewControlle : UIViewController
...
...
...
#property (nonatomic, assign) id delegate; // all you need to do is add this line inside your interface declarations
...
...
...
#end
Then, when you create / instantiate your SecondaryViewControlle from your MainViewController, make certain to add the MainViewController as the delegate like so:
SecondaryViewControlle.delegate = self;
[self.view addSubView:SecondaryViewControlle.view];
Now the "delegate" of your SecondaryViewControlle view controller points back to your MainViewController.
And when the button is pressed, you can simply do something like:
- (IBAction) buttonIsPressed: (id) sender
{
[delegate doSomething];
}
Now, I need to give you some advice here.
1 ) DO NOT use the class names as object names. Instead of having an object named "SecondViewControlle", name it something different (and start it with a lower case, which is Objective-C convention), something like "moreDetailVC".
2) I've told you how to do this with a delegate pattern, but this may not be the most appropriate way to do whatever it is that you're trying to do. After all, the MainViewController object (which should be renamed mainVC to differentiate the object from the class) is not on screen or visible so maybe there's a better place to put the functionality?
Option A
It's quicker, and easier, but lacks the maintainability, since there is no contract stating that SecondaryViewController needs to bother calling anything, and self.parentViewController could be any UIViewController.
Option B
The delegate pattern; this is my preference, it's obvious what's happening, what's required, and there's a nice solid contract that states, if you want to initialise me, give me a delegate.
Option C
If SecondaryViewController has to notify multiple objects, it would be quick to use the NSNotificationCenter, but as with Option A, there's no contract, should you need to notify many objects, you would need to remember to listen for notifications on those objects - since this is not the question, I won't go into detail, it's just here for the information
Option A
Within MainViewController.m, do something like so:
SecondaryViewController *viewcontroller = [[SecondaryViewController alloc] initWithNibName:#"SecondaryView" bundle:nil];
[self addChildViewController:viewcontroller];
//set viewcontroller.view frame
[self.view addSubview:viewcontroller.view];
[viewcontroller didMoveToParentViewController:self];
Inside MainViewController.h
-(void) performButtonClickAction;
Inside MainViewController.m:
-(void) performButtonClickAction {
//Do something constructive
}
and then inside the SecondaryViewController.m:
-(IBAction) buttonPressed:(id) sender {
[self.parentViewController performButtonClickAction];
}
Option B
Inside SecondaryViewController.h
#protocol SecondaryViewControllerDelegate <NSObject>
-(void) eventAFromViewController:(UIViewController *) viewController;
-(void) eventBFromViewController:(UIViewController *) viewController;
#end
#interface SecondaryViewController : UIViewController {
id<SecondaryViewControllerDelegate> delegate;
}
#property (assign, nonatomic) id<SecondaryViewControllerDelegate> delegate;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil delegate:(id<SecondaryViewControllerDelegate>) theDelegate;
#end
Inside SecondaryViewController.m
#synthesize delegate = _delegate;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil delegate:(id<SecondaryViewControllerDelegate>) theDelegate
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.delegate = theDelegate;
}
return self;
}
-(IBAction) buttonPressed:(id) sender {
if( self.delegate != nil ) {
[_delegate eventAFromViewController:self];
}
else {
//No delegate
}
}

Hide TableView declared in other class

How to hide my tableView which is declared in another class..
Here is my code snippet,
CRStoreView.h
#interface CRStoreView : UIView <UITableViewDelegate, UITableViewDataSource>{
....
}
#property (strong, nonatomic) IBOutlet UITableView *tblStore;
and i want to hide this tblStore in my new class(CRNextView.m)..
I tried this but table is not getting hide,
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"touchesBegan");
CRStoreView *Obj = [[CRStoreView alloc] init];
[Obj.tblStore setHidden:YES];
}
How to Solve it ?
One method is to use delegates. Make CRStoreView a delegate of the CRNextView and call the setHidden method from the CRNextView on the delegate. Or you could pass the current instance of the CRStoreView to CRNextView and access the tableView object.

How to pass digit or data from subclassed UIView to UIViewController?

I have subclassed UITableViewController and inside table I have custom cells. And this custom cells have subclassed UIView inside. So this UIView is written in its own class. In my code the UITableViewController class is named MainViewController.h/.m and UIView's class is named ContentView.h/.m So in ContentView I added an image and tapGestureRecognizer. To when the image is tapped some date(in this case digit) is send to MainViewController. The first problem is that the delegate method does not get called. And if I call it with notificationCenter it logged it as 0.00000 Can someone help me to pass data from view inside cell to ViewController.
This is my code:
ContentView.h:
#class ContentView;
#protocol ContentViewDelegate
- (void)passDigit:(float)someDigit;
#end
#import <UIKit/UIKit.h>
#import "MainViewController.h"
#interface ContentView : UIView
{
id <ContentViewDelegate> delegate;
float someDigit;
}
#property float someDigit;
#property (assign) id <ContentViewDelegate> delegate;
#end
ContentView.m
#import "ContentView.h"
#implementation ContentView
#synthesize someDigit;
#synthesize delegate;
- (void)handleContentTouch:(UIGestureRecognizer *)gesture
{
someDigit = 134;
[self.delegate passDigit:someDigit];
}
- (void)setupView
{
CGRect frame = self.frame;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(handleContentTouch:)];
UIImageView *fifthBackground = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,100,100)];
[self addSubview:fifthBackground];
[fifthBackground setUserInteractionEnabled:YES];
[fifthBackground addGestureRecognizer:tap];
}
MainViewController.h
#import <UIKit/UIKit.h>
#import "ContentView.h"
#interface MainViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource, UIScrollViewDelegate, ContentViewDelegate>
#end
MainViewContorller.m
#import "MainViewController.h"
#implementation MainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
ContentView *contentView = [[ContentView alloc]initWithFrame:CGRectMake(0, 0, 320, 480)];
contentView.delegate = self;
}
- (void) passDigit:(float)someDigit
{
NSLog(#"%f",someDigit);
}
Not sure what you are trying to do, may be you are new and learning out some things. Try doing the following:
Change your method in mainViewController
- (void) showDetailViewControllerWithDigit:(float)someDigit
{
NSLog(#"%f",someDigit);
}
to
- (void)passDigit:(float)someDigit
{
NSLog(#"%f",someDigit);
}
and it should work. Also not very relevant here but you have spelled delegate and delegete in two different places. Be mindful that they both will be considered as two different variables. Though not necessary to have an instance variable with the same name, I would definitely not have it with a slight typo, because it will cause a lot of problems later.
When you define a protocol for a delegate, the methods you have defined there should be implemented in the delegate class.
Also in your code you have, obviously you have missed some parts, which show as to where you are adding the contentView in the main view controller. I am assuming that some where you have
[self.view addSubview:contentView];
in the viewDidLoad or some where, without which you cannot even see the contentView and there fore cannot tap it.
Happy coding.

Return NSString from UIViewController

I want to return a NSString * from a UIViewController, called InputUIViewController, to the previous UIViewController, called CallerUIViewController, which started InputUIViewController. I want to do it just before or when InputUIViewController calls:
[self dismissModelViewControllerAnimated:YES];
Is there a standard way to do this?
The standard way to do this would be to use a delegate.
In your InputViewController add a new delegate protocal, and a property for your delegate.
Then in your CallerUIViewController implement the delegate. Then just before your dismiss the modal view controller you can call back to your delegate.
So your InputViewController might look like this:
#protocol InputViewControllerDelegate;
#interface InputViewControllerDelegate : UIViewController {
}
#property (nonatomic, assign) id <InputViewControllerDelegate> delegate;
#end
#protocol InputViewControllerDelegate
- (void)didFinishWithInputView:(NSString *)stringValue;
#end
The method that dismisses the modal view would look something like this:
-(void)dismissSelf
{
[self.delegate didFinishWithInputView:#"MY STRING VALUE"];
[self dismissModalViewControllerAnimated:YES];
}
Then in your CallerUIViewController you would implement the InputViewControllerDelegate and the didFinishWithInputView method.
The CallerUIViewController header would look something like:
#interface CallerUIViewController : UIViewController <InputViewControllerDelegate> {
}
and your didFinishWithInputView method would be implemented something like:
- (void)didFinishWithInputView:(NSString *)stringValue
{
// This method will be called by the InputViewController just before it is dismissed
}
Just before your present the InputViewController you would set the delegate to self.
-(void)showInputViewController
{
InputViewController *inputVC = [[InputViewController alloc] init];
inputVC.delegate = self;
[self presentModalViewController:inputVC animated:YES];
[inputVC release];
}
You can do this by simply creating a NSString object as property in prvious view controller and when in second view you call dismissModelViewControllerAnimated then before it assign value to previous view controller property. This might help you -
Passing data between classes using Objective-C