Trouble setting UISwitch in FlipsideViewController - iphone

I have an iPhone utility app from the standard template, so I have MainViewController and FlipsideViewController that gets initialized and called controller. In controller's xib I have a UISwitch called pathSwitch and a UISegmentedControl called locationSelector that are outlets (and hooked up!) When I call the showInfo:(id)sender method, I do the following:
[EDIT] Adding the interface of the controller...
[EDIT 2] Updated interface to show added properties
- (IBAction)showInfo:(id)sender {
ALog(#"method begin...");
FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:#"FlipsideView" bundle:nil];
DLog(#">sun path visible = %#, setting flip side controller switch", sunPathIsVisible ? #"YES" : #"NO");
// deleted -> [controller.pathSwitch setOn:sunPathIsVisible];
controller.sunPathIsVisible = sunPathIsVisible; // added this
DLog(#">location mode is %d, setting flip side controller segment index to %d - 1 = %d", locationMode, locationMode, locationMode - 1);
// deleted -> controller.locationSelector.selectedSegmentIndex = locationMode - 1;
controller.delegate = self;
controller.locationMode = locationMode; // added this
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:controller animated:YES];
[controller release];
}
#interface FlipsideViewController : UIViewController {
id <FlipsideViewControllerDelegate> delegate;
int locationMode; // added this
UISegmentedControl *locationSelector;
BOOL sunPathIsVisible;
UISwitch *pathSwitch;
}
#property (nonatomic, assign) id <FlipsideViewControllerDelegate> delegate;
#property int locationMode; // added this
#property (nonatomic, retain) IBOutlet UISegmentedControl *locationSelector;
#property BOOL sunPathIsVisible; // added this
#property (nonatomic, retain) IBOutlet UISwitch *pathSwitch;;
- (IBAction)done:(id)sender;
- (IBAction)cancel:(id)sender;
#end
// There's also the `protocol` stuff, but I left that out here...
The problem is that the controls do not accept their values and always show segment 0 and OFF. If I set their properties in controller's viewWillAppear method, they do show the correct setting.
Is controller not fully loaded when I do this or something?

You're probably right. The cleanest way would be to add some properties to the FlipsideViewController, and set those. Then let viewWillAppear set the actual switches using these properties.
This will also put the UI layout issues of FlipsideViewController where they belong, namely in FlipsideViewController and not in any other controller that may ever use it. (i.e. if you ever decide to not use a switch but some kind of button, you can change FlipsideViewController without having to look at other code)
edit
Some clarification. Try to add properties to FlipsideViewController with these lines at the relevant places:
BOOL switchState;
NSInteger locationMode;
#property (nonatomic,assign) BOOL switchState;
#property (nonatomic,assign) NSInteger locationMode;
#synthesize switchState;
#synthesize locationMode;
Then, in your current -(IBAction)showInfo:(id)sender you could say:
FlipsideViewController *controller = [[FlipsideViewController alloc]
initWithNibName:#"FlipsideView" bundle:nil];
controller.switchState = sunPathIsVisible;
controller.locationMode = locationMode;
controller.delegate = self;
// etc etc
Then, in FlipsideViewController, in viewDidLoad, put the actual handling of the switch value:
[self.pathSwitch setOn:self.sunPathIsVisible];
[self.locationSelector setSelectedSegmentIndex:self.locationMode];
This will a) solve your problem and b) separate your concerns regarding the user interface. If you would decide to change the layout of FlipsideViewController, there is no need to change any code other than that of FlipsideViewController.
There are other ways of achieving this, e.g. by letting your viewDidLoad fetch the value from its delegate, which would look like:
[self.pathSwitch setOn:[delegate pathSwitch]];
Which may be better, depending on your situation. Generally speaking I would always prefer this last approach, since it prevents synchronisation issues between your different view controllers.

I am not sure but shouldn't this be
#property (nonatomic, retain) IBOutlet UISegmentedControl *locationSelector;
#property (nonatomic, retain) IBOutlet UISwitch *pathSwitch;
instead of
#property (nonatomic, assign) IBOutlet UISegmentedControl *locationSelector;
#property (nonatomic, assign) IBOutlet UISwitch *pathSwitch;;

Related

Change text in UILabel with NSMutablearray data

I'm trying to change the text of a UILabel with text from an array upon a button click, but it doesn't do anything.
#interface Test01AppDelegate : NSObject <UIApplicationDelegate> {
UILabel *helloLabel;
UIButton *hellobutton;
NSMutableArray *madWords;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UIButton *hellowButton;
#property (nonatomic, retain) IBOutlet UILabel *hellowLabel;
#property (nonatomic, retain) NSMutableArray *madWords;
- (void) madArrays;
- (IBAction)helloYall;
#end
and
#import "Test01AppDelegate.h"
#implementation Test01AppDelegate
#synthesize window = _window;
#synthesize hellowButton;
#synthesize hellowLabel;
#synthesize madWords;
- (void) madArrays {
[madWords addObject:#"Part A"];
[madWords addObject:#"Part B"];
[madWords addObject:#"Part C"];
[madWords addObject:#"Part D"];
}
- (IBAction)helloYall {
[self madArrays];
self.hellowLabel.text = [madWords objectAtIndex:0];
}
I can set the helloLabel text with
#"some text here";
and it works fine. Also, I tried copying the "madArrays" method into the "helloYall" method and it still didn't work. As I said, I can manually set the text and it works, but I'd like to pull the info from an array. Eventually, I'd like to loop through the array to grab the text on each button press, but one step at a time. Thanks.
You never create the madWords array. You need to add:
self.madWords = [NSMutableArray array];
at the top of:
- (void) madArrays {
would probably be a good place. Other possibly good places would be i the class init method or the view controller viewWillAppear method.
// Or you can try this in your init Method:
//first allocate the ivar
- (void)myInitMethod {
madArrays = [[NSMutableArray]alloc]init];
}
//then you can do anything directly to the ivar or throughout de setter
- (void)doAnythingWithiVar {
// do your stuff
}
//when you are done you can dealloc your ivar
- (void)dealloc {
[madArrays release];
[super dealloc];
}
It looks like madArrays is still nil when you come to populate it. At some point you need something like [self setMadArrays:[[NSMutableArray alloc] init]];. Also, don't forget to release madArrays in the dealloc before calling super as you'll have a memory leak.

UIPopover Delegate - Unable to assign regardless of protocal/declarations

I'm having some difficulty figure out what I'm doing wrong when trying to assign my a delegate for my UIPopoverView. I tried to work around not even using one, but having it would be much more straightforward and clean. Here is the code that I think should cover it:
//.h of View where I call popover, this would be the delegate.
#import <UIKit/UIKit.h>
#import "ACTypePopoverViewController.h"
#interface NewRouteViewController : UIViewController<ACTypePickerDelegate>{
ACTypePopoverViewController *_acTypePicker;
UIPopoverController *_acTypePickerPopover;
}
#property (nonatomic, retain) ACTypePopoverViewController *acTypePicker;
#property (nonatomic, retain) UIPopoverController *acTypePickerPopover;
#end
//.m file for where I would like to use the popover, is the .m for the .h above
if (_acTypePickerPopover == nil)
{
ACTypePopoverViewController* content = [[ACTypePopoverViewController alloc] init];
UIPopoverController* aPopover = [[UIPopoverController alloc]
initWithContentViewController:content];
aPopover.delegate = self;
[content release];
// Store the popover in a custom property for later use.
self.acTypePickerPopover = aPopover;
}
[self.acTypePickerPopover presentPopoverFromRect:self.selectACTypeButton.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
//.h file for the actual popover, what I would be setting the delegate of
#protocol ACTypePickerDelegate
- (void)acTypeSelected:(NSString *)acType;
#end
#interface ACTypePopoverViewController : UITableViewController {
NSMutableArray *_acTypes;
NSString *selectedACType;
id<ACTypePickerDelegate> _delegate;
}
#property (nonatomic, retain) NSMutableArray *acTypes;
#property (nonatomic, retain) NSString *selectedACType;
#property (nonatomic, assign) id<ACTypePickerDelegate> delegate;
#end
I think thats all I need, but let me know if more code is needed!
Thanks!
I understood you correctly... what you need is:
content.delegate = self;
Right after this line you have:
ACTypePopoverViewController* content = [[ACTypePopoverViewController alloc] init];
Are you synthesizing your properties? Also you are assigning your delegate before initiating the popover...
#synthesize acTypePickerPopover;
self.acTypePickerPopover = [[[UIPopoverController alloc]
initWithContentViewController:_acTypePickerPopover] autorelease];
self.acTypePickerPopover.delegate = self;
`

Objective-c Novice - Needs help with UIViews

Im new to iphone development and after lots of reading on it im still trying to figure out how UIViews operate properly. I have been playing about with it and i this is where i am at so far:
I have created a new xcode project using the view-based application. I have my MMAppViewController classes and i created a new UIViewController subclass called "Level1View".
There is a button titled "Level 1" that takes me to the "Level1View" viewController. In this viewController there is there is a "next" button, a "main menu" button (that returns to MMAppViewController) and there is a label, currently titled "Level 1".
My problem is that the code i have used to change the title of label does not work! Does anyone know why this is? Here is my code:
#class MMAppViewController;
#interface MMAppAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
MMAppViewController *viewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet MMAppViewController *viewController;
#end
and
#implementation MMAppViewController
-(IBAction)pushLevel1{
Level1View *level1View = [[Level1View alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:level1View animated:YES];
}
...
and
#import <UIKit/UIKit.h>
#interface Level1View : UIViewController {
IBOutlet UILabel *labelTitle;
}
-(IBAction)pushBack;
-(IBAction)pushNext;
#end
and
#import "Level1View.h"
#import "MMAppViewController.h"
#implementation Level1View
-(IBAction)pushBack{
MMAppViewController *MainView = [[MMAppViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:MainView animated:YES];
}
-(IBAction)pushNext{
[labelTitle setText:(#"Thanks for playing :)")];
}
- (void)didReceiveMemoryWarning {
...
Currently the app runs but the label wont change when i hit the "next" button. Can anyone help?
are you sure a UINavigationController isn't a better tool for the job you want to do? That will make it easy for you to manage a stack of UIView objects.
That said, have you tried adding logging to make sure your pushNext method is getting called? where is labelTitle declared? Did you use a XIB or not?
Did you bind the Label in Interface Builder to the labelTitle outlet in your Level1View?
If you forget that step, the outlets won't work. Even after several years, I still forget this step sometimes.
--Mike
are you sure you connected the label in IB?
and if you set a property "#property (nonatomic, retain) IBOutlet UILabel *labelTitle;" in Level1View.h you can access it from Main View:
Level1View *level1View = [[Level1View alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:level1View animated:YES];
level1View.labelTitle.text = #"something";
[level1View release];
The other thing you shouldn't present the Main View Controller again instead dismiss the Level1View with:
#implementation Level1View
-(IBAction)pushBack{
[self dismissModalViewControllerAnimated:YES];
}
//
and maybe the problem is [[Level1View alloc] initWithNibName:nil bundle:nil] you have to specify the nib you want to load e.g. [[Level1View alloc] initWithNibName:#"Level1View" bundle:nil]
Declare labelTitle as a property in your header file, and synthesize labelTitle in your .m - as long as labelTitle is hooked up through interface builder the rest of your code is fine.
.h
#property (nonatomic, retain) IBOutlet UILabel *labelTitle;
.m
#synthesize labelTitle;
Then your setter call will work. (also, dot-notation works for synthesized properties so you may as well use it)
change
[labelTitle setText:(#"Thanks for playing :)")];
to
labelTitle.text = #"Thanks for playing :)";
Synthesizing a property will create setter and getter methods at runtime. Read: The Objective-C Programming Language

How do I add a custom view to iPhone app's UI?

I'm diving into iPad development and I'm still learning how everything works together. I understand how to add standard view (i.e. buttons, tableviews, datepicker, etc.) to my UI using both Xcode and Interface Builder, but now I'm trying to add a custom calendar control (TapkuLibrary) to the left window in my UISplitView application which doesn't involve Interface Builder, right? So if I have a custom view (in this case, the TKCalendarMonthView), how do I programmatically add it to one of the views in my UI (in this case, the RootViewController)? Below are some relevant code snippets from my project...
RootViewController interface
#interface RootViewController : UITableViewController <NSFetchedResultsControllerDelegate> {
DetailViewController *detailViewController;
NSFetchedResultsController *fetchedResultsController;
NSManagedObjectContext *managedObjectContext;
}
#property (nonatomic, retain) IBOutlet DetailViewController *detailViewController;
#property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
- (void)insertNewObject:(id)sender;
TKCalendarMonthView interface
#class TKMonthGridView,TKCalendarDayView;
#protocol TKCalendarMonthViewDelegate, TKCalendarMonthViewDataSource;
#interface TKCalendarMonthView : UIView {
id <TKCalendarMonthViewDelegate> delegate;
id <TKCalendarMonthViewDataSource> dataSource;
NSDate *currentMonth;
NSDate *selectedMonth;
NSMutableArray *deck;
UIButton *left;
NSString *monthYear;
UIButton *right;
UIImageView *shadow;
UIScrollView *scrollView;
}
#property (readonly,nonatomic) NSString *monthYear;
#property (readonly,nonatomic) NSDate *monthDate;
#property (assign,nonatomic) id <TKCalendarMonthViewDataSource> dataSource;
#property (assign,nonatomic) id <TKCalendarMonthViewDelegate> delegate;
- (id) init;
- (void) reload;
- (void) selectDate:(NSDate *)date;
Thanks in advance for all your help! I still have a ton to learn, so I apologize if the question is absurd in any way. I'm going to continue researching this question right now!
Assuming you have initialized the custom UIView, you need to add it as a subview of the viewController's view.
- (void)addSubview:(UIView *)view
So an example would be if you have a plain viewController called myVC, which has simply a blank white UIView as its view, you would say this:
CGRect customViewsFrame = CGRectMake(10, 30, 5, 2);
MyCustomView *myView = [[MyCustomView alloc] initWithFrame:customViewsFrame];
[[myVC view] addSubview:myView];
[myView release]; //Since you called "alloc" on this, you have to release it too
Then it will show up in the viewController's view, taking up the space indicated by the CGRect.
The CGRect's coordinates specify a location in the local coordinate system of the superview you are adding to, if I'm not mistaken.
CGRect CGRectMake (CGFloat x, CGFloat y, CGFloat width, CGFloat height);
I'm not booted into Mac OS X so I can't verify this completely, but this is your general pattern:
RootViewController.h:
...
#interface RootViewController : UITableViewController <NSFetchedResultsControllerDelegate>
{
...
TKCalendarMonthView* calendarView;
...
}
...
#property (nonatomic, retain) TKCalendarMonthView* calendarView;
...
RootViewController.m:
...
#synthesize calendarView;
...
- (void)dealloc
{
...
[calendarView release];
...
}
...
- (void)viewDidLoad
{
...
TKCalendarMonthView* aCalendarView = [[TKCalendarMonthView alloc] init]; // <-- possibly initWithFrame here
self.calendarView = aCalendarView;
[aCalendarView release];
[self addSubview:self.calendarView];
...
}

Calling a function from another UIViewController

I'm a beginner programmmer, this is for xcode - iPhone. although i made alot of my iPhone app but i seem to lack some understanding of how a simple communication might work.
Specially when I've got 2 ViewControllers.
And I wana call one function of a ViewController from another ViewController. Both are under a tabbarController. What I want to achieve is When I'm in ViewA, after tapping on a tableCell, I Should Invoke a method of ViewB and the NavigationBar of ViewB pushes to viewDetail.
The Following is the code i'm using
in ViewControllerA.h (where I'm calling a method)
#class ViewControllerB;
#interface SmartDDxViewController : UIViewController {
IBOutlet UITableView *tableView;
ViewControllerB *xViewController;
}
#property (nonatomic, retain) UITableView *tableView;
#property (nonatomic, retain) ViewControllerB *xViewController;
And this is what I use to invoke it..ViewControllerA.m
ViewControllerB *ddViewController = [[ViewControllerB alloc] init];
self.xViewController = ddViewController;
[xViewController InitialiseDetailWithId:2 title:#"HEYA"];
Heres the InitialiseDetailWithId code: in ViewControllerB.m
-(void)InitialiseDetailWithId:(NSInteger)pkey title:(NSString *)tt{
NSLog(#"InitialiseDetailC=========================================");
AppDelegate *appDelegate = (Smart_DifferentialsAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate GetConditionDetailsWithId:pkey];
DDisViewController *viewController= [[DDisViewController alloc] initWithNibName:#"DetailView" bundle:nil];
viewController.title = tt;
[self.NavBar pushViewController:viewController animated:YES];
//[tt release];
[viewController release];
viewController = nil;
[self say:#"HEYA"]; //this is ALERTVIEW box that displays HEYA
}
I'm getting all information fine, and the alertview does get displayed. But when I chose that View in TabBar, its not pushed.
Do not use direct access between view controllers, instead use the delegate pattern. Define your controller like this:
#protocol ViewControllerAInitDelegate;
#interface ViewControllerA : UIViewController {
IBOutlet UITableView *tableView;
id<ViewControllerAInitDelegate> initDelegate;
}
#property (nonatomic, retain) UITableView *tableView;
#property (nonatomic, assign) ViewControllerAInitDelegate *initDelegate;
#end
#protocol ViewControllerInitDelegate
-(void)initializeDetailWithId:(NSInteger)pkey title:(NSString)tt;
#end
So in
Now let your application delegate conform to the ViewControllerInitDelegate protocol. It should look something like this:
#interface AppDelegate : NSObject <UIApplicationDelegate, ViewControllerInitDelegate> {
IBOutlet UITabBarControler* tabBarController;
IBOutlet ViewControllerA* controllerA;
IBOutlet ViewControllerB* controllerB;
}
#end;
The AppDelegate should know about both ViewControllerA, and ViewControllerB, but neither of the view controller should know about each other. This way it will be much easier to debug and extend your app.
//current view controller index
int currentVCIndex = [self.navigationController.viewControllers indexOfObject:self.navigationController.topViewController];
//previous view controller (index -1)
AccountViewController *account = (AccountViewController *)[self.navigationController.viewControllers objectAtIndex:currentVCIndex - 1];
(access to anything you want)
account.property = object;
[account doSmthng];
In each of your view controllers, you might want to add a instance variable/property to keep track of the other view controller.
you might have for example:
#interface ThisViewController : UIViewController {
SomeViewController *sViewController;
// other instance variables
}
#property (nonatomic, retain) SomeViewController *sViewController;
This not only makes it easier to call methods from the other view controller and access its public properties, but it also allows you an easier way of flipping between the two (with or without animation).