I have 3 classes:
LocalRoom.m
- (void) handleNewConnection:(Connection*)connection {
NSString* number = #"10";
AppDelegate *theAppDelegate = [[NSApplication sharedApplication] delegate];
[theAppDelegate connectionNumber:number currentZoneName:#"Zone1";
}
Triggers ----->
AppDelegate.h
MyTableController *tableController;
AppDelegate.m
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
tableController = [[MyTableController alloc] init];
}
- (void)connectionNumber:(NSString *)number zoneName:(NSString *)currentZoneName {
if ([currentZoneName isEqualToString:zoneName1]) {
[tableController changeConnections:number withRowNumber:0];
}
}
Triggers ----->
MyTableController.h
#interface MyTableController : NSControl {
IBOutlet NSTextField *zoneNameTextField;
}
#property (retain) NSTableView * idTableView;
- (void) changeConnections:(NSString *)number withRowNumber:(int)rowNumber;
MyTableController.m
- (void) changeConnections:(NSString *) number withRowNumber:(int) rowNumber{
NSRunAlertPanel([NSString stringWithFormat:#"%d", rowNumber], number, #"", #"", #"");
NSTableColumn *tableColumn = [[NSTableColumn alloc] initWithIdentifier: #"Connections"];
[self tableView:idTableView setObjectValue:number forTableColumn:tableColumn row:rowNumber];
[idTableView reloadData];
}
My NSRunAlertPanel is coming up with the correct values, but my NSTextView is not changing. When I put the "edit" code for the NSTableView in an IBAction of MyTableController.m, it works. I checked if idTableView was NULL, and it was. Which is weird. So, I have a feeling something odd is happening when changeConnections is run by the AppDelegate. I had a similar problem with a nstextfield not returning data. The fix was to initialize it by AppDelegate *theAppDelegate = [[NSApplication sharedApplication] delegate]; Is there something similar in this case?
You might wonder why I'm just not calling MyTableController from LocalRoom, but "zoneName1" is set and found in the app delegate.
Thanks in advance!
You haven't shown all the code, but idTableView is declared as a #property of MyTableController, but not as an IBOutlet.
That is idTableView being NULL strongly suggests that the idTableView property is never set to the appropriate table view. No IBOutlet for it means it can't be connected in the NIB/XIB. So the fix is probably to make it an outlet and connect it in the NIB.
Obviously, [idTableView reloadData] has no effect if idTableView is NULL.
I assume that your NIB does set MyTableController as its table data delegate, which is why the direct editing would work.
Further, although I don't think this is related to your problem, for best practice it doesn't make sense to manufacture a new NSTableColumn to work on your existing table -- you should be using [idTableView tableColumnWithIdentifier: #"Connections"] instead.
Related
I use storyboard in a OS X cocoa application project with a SplitView controller and 2 others view controller LeftViewController and RightViewController.
In the LeftViewController i have a tableView that display an array of name. The datasource and delegate of the tableview is the LeftViewController.
In the RightViewController i just have a centered label that display the select name. I want to display in the right view the name selected in the left view.
To configure the communication between the 2 views controllers i use the AppDelegate and i define 2 property for each controller in AppDelegate.h
The 2 property are initialized in the viewDidLoad of view controller using the NSInvocation bellow :
#implementation RightViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
id delg = [[NSApplication sharedApplication] delegate];
SEL sel1 = NSSelectorFromString(#"setRightViewController:");
NSMethodSignature * mySignature1 = [delg methodSignatureForSelector:sel1];
NSInvocation * myInvocation1 = [NSInvocation
invocationWithMethodSignature:mySignature1];
id me = self;
[myInvocation1 setTarget:delg];
[myInvocation1 setSelector:sel1];
[myInvocation1 setArgument:&me atIndex:2];
[myInvocation1 invoke];
}
I have the same in LeftViewController.
Then if i click on a name in the table view, i send a message to the delegate with the name in parameter and the delegate update the label of the RightViewController with the given name. It works fine but according to apple best practice it’s not good.
Is there another way to communicate between 2 view controller inside a storyboard ?
I've already read a lot of post but found nothing for OS X.
You can download the simple project here : http://we.tl/4rAl9HHIf1
This is more advanced topic of app architecture (how to pass data).
Dirty quick solution: post NSNotification together with forgotten representedObject:
All NSViewControllers have a nice property of type id called representedObject. This is one of the ways how to pass data onto NSViewController. Bind your label to this property. For this simple example we will set representedObject some NSString instance. You can use complex object structure as well. Someone can explain in comments why storyboards stopped to show representedObject (Type safety in swift?)
Next we add notification observer and set represented object in handler.
#implementation RightViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserverForName:#"SelectionDidChange" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
//[note object] contains our NSString instance
[self setRepresentedObject:[note object]];
}];
}
#end
Left view controller and its table:
Once selection changes we post a notification with our string.
#interface RightViewController () <NSTableViewDelegate, NSTableViewDataSource>
#end
#implementation RightViewController
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
return [[self names] count];
}
- (nullable id)tableView:(NSTableView *)tableView objectValueForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row
{
return [self names][row];
}
- (NSArray<NSString *>*)names
{
return #[#"Cony", #"Brown", #"James", #"Mark", #"Kris"];
}
- (void)tableViewSelectionDidChange:(NSNotification *)notification
{
NSTableView *tableView = [notification object];
NSInteger selectedRow = [tableView selectedRow];
if (selectedRow >= 0) {
NSString *name = [self names][selectedRow];
if (name) {
[[NSNotificationCenter defaultCenter] postNotificationName:#"SelectionDidChange" object:name];
}
}
}
PS: don't forget to hook tableview datasource and delegate in storyboard
Why is this solution dirty? Because once your app grows you will end up in notification hell. Also view controller as data owner? I prefer window controller/appdelegate to be Model owner.
Result:
AppDelegate as Model owner.
Our left view controller will get it's data from AppDelegate. It is important that AppDelegate controls the data flow and sets the data (not the view controller asking AppDelegate it's table content cause you will end up in data synchronization mess). We can do this again using representedObject. Once it's set we reload our table (there are more advanced solutions like NSArrayController and bindings). Don't forget to hook tableView in storyboard. We also modify tableview's delegate methos the tableViewSelectionDidChange to modify our model object (AppDelegate.selectedName)
#import "LeftViewController.h"
#import "AppDelegate.h"
#interface LeftViewController () <NSTableViewDelegate, NSTableViewDataSource>
#property (weak) IBOutlet NSTableView *tableView;
#end
#implementation LeftViewController
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
return [[self representedObject] count];
}
- (nullable id)tableView:(NSTableView *)tableView objectValueForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row
{
return [self representedObject][row];
}
- (void)setRepresentedObject:(id)representedObject
{
[super setRepresentedObject:representedObject];
//we need to reload table contents once
[[self tableView] reloadData];
}
- (void)tableViewSelectionDidChange:(NSNotification *)notification
{
NSTableView *tableView = [notification object];
NSInteger selectedRow = [tableView selectedRow];
if (selectedRow >= 0) {
NSString *name = [self representedObject][selectedRow];
[(AppDelegate *)[NSApp delegate] setSelectedName:name];
} else {
[(AppDelegate *)[NSApp delegate] setSelectedName:nil];
}
}
In RightViewController we delete all code. Why? Cause we will use binding AppDelegate.selectedName <--> RightViewController.representedObject
#implementation RightViewController
#end
Finally AppDelegate. It needs to expose some properties. What is interesting is how do I get my hands on all my controllers? One way (best) is to instantiate our own window controller and remember it as property. The other way is to ask NSApp for it's windows (be careful here with multiwindow app). From there we just ask contentViewController and loop through childViewControllers. Once we have our controllers we just set/bind represented objects.
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (nonatomic) NSString *selectedName;
#property (nonatomic) NSMutableArray <NSString *>*names;
#end
#import "AppDelegate.h"
#import "RightViewController.h"
#import "LeftViewController.h"
#interface AppDelegate () {
}
#property (weak, nonatomic) RightViewController *rightSplitViewController;
#property (weak, nonatomic) LeftViewController *leftSplitViewController;
#property (strong, nonatomic) NSWindowController *windowController;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
_names = [#[#"Cony", #"Brown", #"James", #"Mark", #"Kris"] mutableCopy];
_selectedName = nil;
NSStoryboard *storyboard = [NSStoryboard storyboardWithName:#"Main"
bundle:[NSBundle mainBundle]];
NSWindowController *windowController = [storyboard instantiateControllerWithIdentifier:#"windowWC"];
[self setWindowController:windowController];
[[self windowController] showWindow:nil];
[[self leftSplitViewController] setRepresentedObject:[self names]];
[[self rightSplitViewController] bind:#"representedObject" toObject:self withKeyPath:#"selectedName" options:nil];
}
- (RightViewController *)rightSplitViewController
{
if (!_rightSplitViewController) {
NSArray<NSViewController *>*vcs = [[[self window] contentViewController] childViewControllers];
for (NSViewController *vc in vcs) {
if ([vc isKindOfClass:[RightViewController class]]) {
_rightSplitViewController = (RightViewController *)vc;
break;
}
}
}
return _rightSplitViewController;
}
- (LeftViewController *)leftSplitViewController
{
if (!_leftSplitViewController) {
NSArray<NSViewController *>*vcs = [[[self window] contentViewController] childViewControllers];
for (NSViewController *vc in vcs) {
if ([vc isKindOfClass:[LeftViewController class]]) {
_leftSplitViewController = (LeftViewController *)vc;
break;
}
}
}
return _leftSplitViewController;
}
- (NSWindow *)window
{
return [[self windowController] window];
}
//VALID SOLUTION IF YOU DON'T INSTANTIATE STORYBOARD
//- (NSWindow *)window
//{
// return [[NSApp windows] firstObject];
//}
#end
Result: works exactly the same
PS: If you instantiate own window Controller don't forget to delete initial controller from Storyboard
Why is this better? Cause all changes goes to model and models sends triggers to redraw views. Also you will end up in smaller view controllers.
What can be done more? NSObjectController is the best glue between your model objects and views. It also prevents retain cycle that sometimes can happen with bindings (more advanced topic). NSArrayController and so on...
Caveats: not a solution for XIBs
I managed to get what i want by adding the following code in AppDelegate.m :
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
//
NSStoryboard *storyboard = [NSStoryboard storyboardWithName:#"Main"
bundle:[NSBundle mainBundle]];
self.windowController = [storyboard instantiateControllerWithIdentifier:#"windowController"];
self.window = self.windowController.window;
self.splitViewController = (NSSplitViewController*)self.windowController.contentViewController;
NSSplitViewItem *item0 = [self.splitViewController.splitViewItems objectAtIndex:0];
NSSplitViewItem *item1 = [self.splitViewController.splitViewItems objectAtIndex:1];
self.leftViewController = (OMNLeftViewController*)item0.viewController;
self.rightViewController = (OMNRightViewController*)item1.viewController;
[self.window makeKeyAndOrderFront:self];
[self.windowController showWindow:nil];
}
We also need to edit the storyboard NSWindowController object as follow :
Uncheck the checkbox 'Is initial controller' because we add it programmatically in AppDelegate.m.
Now the left and right view can communicate. Just define a property named rightView in OMNLeftViewController.h :
self.leftViewController.rightView = self.rightViewController;
I'm showing an NSPopover in an NSView, originating from a point on an NSBezierPath. I'm able to show the popover without a problem, but I can't seem to set the string value of the two text fields in it. The popover and the content view are both a custom subclass of NSPopover and NSViewController, respectively. The NSPopover subclass is also the NSPopover's delegate, although I don't implement any delegate methods, so I'm not sure I even need to do that.
Here is my subclass of NSViewController:
#import <Cocoa/Cocoa.h>
#interface WeightPopoverViewController : NSViewController
#end
#import "WeightPopoverViewController.h"
#interface WeightPopoverViewController ()
#end
#implementation WeightPopoverViewController
- (id)init {
self = [super initWithNibName:#"WeightPopoverViewController" bundle:nil];
if (self) {
}
return self;
}
#end
And my subclass of NSPopover:
#import <Cocoa/Cocoa.h>
#interface WeightPopoverController : NSPopover <NSPopoverDelegate> {
NSTextField *dateLabel;
NSTextField *weightLabel;
}
#property (strong) IBOutlet NSTextField *dateLabel;
#property (strong) IBOutlet NSTextField *weightLabel;
#end
#import "WeightPopoverController.h"
#implementation WeightPopoverController
#synthesize weightLabel;
#synthesize dateLabel;
#end
This is the code in my NSView subclass that opens up the popover:
#interface WeightGraphViewController () {
WeightPopoverController *popover;
WeightPopoverViewController *vc;
}
...
-(void)mouseEntered:(NSEvent *)theEvent {
// initialize the popover and its view controller
vc = [[WeightPopoverViewController alloc] init];
popover = [[WeightPopoverController alloc] init];
// configure popover
[popover setContentViewController:vc];
[popover setDelegate:popover];
[popover setAnimates:NO];
// set labels
for (id key in (id)[theEvent userData]) {
[popover.weightLabel setStringValue:[(NSDictionary*)[theEvent userData] objectForKey:key]];
[popover.dateLabel setStringValue:key];
}
// set the location
(redacted, irrelevant)
// show popover
[popover showRelativeToRect:rect ofView:[self window].contentView preferredEdge:NSMaxYEdge];
}
-(void)mouseExited:(NSEvent *)theEvent {
[popover close];
popover = nil;
}
In WeightPopoverViewController.xib, I've set the File's Owner to WeightPopoverViewController and connected the view to the custom NSView. In this xib I also have an Object set to WeightPopoverController with the dateLabel and weightLabel connected to their text fields and the contentViewController set to File's Owner.
I think where I am going wrong is likely related to how I have configured my class / instance variables for the NSPopover, but from the research I've done and documentation I've read I can't seem to crack where I've gone wrong. Any help would be appreciated.
UPDATE:
I removed the NSPopover subclass from code and from IB. I put my outlets in my NSViewController and connected them in IB. However, I'm still not able to set the string values. The following won't compile with the error "Property 'weightLabel' not found on object of type NSPopover*'".
#interface WeightGraphViewController () {
NSPopover *popover;
...
}
-(void)mouseEntered:(NSEvent *)theEvent {
vc = [[WeightPopoverViewController alloc] init];
popover = [[NSPopover alloc] init];
[popover setContentViewController:vc];
[popover.dateLabel setStringValue:#"test"];
}
I have the property definition exactly as I had it in my NSPopover subclass, but now in my NSViewController. This is actually what I had before, and since I wasn't able to set the properties from the NSViewController, I figured I needed to do it through a subclass of NSPopover. This is why I thought I am having an issue with how I have configured my class / instance variables.
You seem to be creating two popovers, one in code (popover = [[WeightPopoverController alloc] init]) and one in Interface Builder (In this xib I also have an Object set to WeightPopoverController). Have a think about what you’re trying to achieve.
I would also advise against subclassing NSPopover. I believe this is causing confusion and is unnecessary. Instead, put the outlets to your dateLabel and weightLabel in the popover’s content view controller.
I've experienced something that I think is similar. The root problem is that the "outlets" connecting your view (XIB) to your controller are not initialized until after the view has been displayed. If the controller tries to set properties on any UI controls in the view before the popover has been opened, those changes are ignored (since all the controls will be nil).
Luckily, there's an easy solution (as mentioned in this answer): just invoke the view getter on your controller, and it will force the view to initialize sooner.
In other words:
popover = [NSPopover new];
myController = [[MyViewController alloc] initWithNibName:#"MyView" bundle:nil];
popover.contentViewController = myController;
[myController view]; // force view to initialize
...set some values on myController... // works because view is now loaded
[popover showRelativeToRect: ...];
I'm having some trouble understanding what classes can read what variables in other classes. I've read to many different things online and cant seem to find anything solid in here. I've literally wasted the past two days trying to get my program to work but no classes can read any other classes variables. Any help will be GREATLY appreciated.
This is my ViewController.h:
#interface ViewController : UIViewController
{
#public
NSString *nameOfLabel;
}
#property (strong, nonatomic) IBOutlet UILabel *firstLabel;
- (IBAction)Switch:(id)sender;
- (IBAction)changeLabel:(UIButton *)sender;
-(NSString *) nameOfLabel;
#end
nameOfLabel is a public variable and should be able to be accessed by an outside class, right?
ViewController.m:
#import "ViewController.h"
#import "NewView.h"
#interface ViewController ()
#end
#implementation ViewController
- (IBAction)Switch:(id)sender {
NewView * new = [[NewView alloc] initWithNibName:nil bundle:nil];
[self presentViewController: new animated:YES completion:NULL];
}
- (IBAction)changeLabel:(UIButton *)sender {
nameOfLabel = #"Test Name";
_firstLabel.text = nameOfLabel;
}
-(NSString *) nameOfLabel {
return nameOfLabel;
}
#end
changeLabel button changes *firstLabel.text to "Test name".
second class is NewView.h:
#import "ViewController.h"
#interface NewView : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *secondLabel;
- (IBAction)changeSecondLabel:(UIButton *)sender;
#end
and NewView.m:
#import "NewView.h"
#interface NewView ()
#end
#implementation NewView
{
ViewController *view;
}
- (IBAction)changeSecondLabel:(UIButton *)sender {
view = [[ViewController alloc] init];
_secondLabel.text = view.nameOfLabel;
}
#end
changeSecondLabel should change secondLabel.text to nameOfLabel which is 'Test name', however, the label actually disappears which makes me think that nameOfLabel cannot be reached. Ive played around with nameOfLabel, making it a #property and then synthesising it, as well as trying putting it in { NSString *nameOfLabel; } under #implementation but I still get the same result.
This line: view = [[ViewController alloc] init]; creates a new ViewController which doesn't know anything about what you may have done to some other ViewController. In your case, it specifically doesn't know that changeLabel: was called on another ViewController before this new one ever existed.
When the second view controller (NewView) is presented, it has no reference to the first view controller (ViewController) and it's data.
Here are a couple of suggestions.
In modern Objective-C I'd recommend using properties instead of exposing a variable.
Look over the naming in general. "ViewController" is not a good name for example.
If the property is part of an internal state of the class, declare it in a class extension.
Before you present the second view controller, set a reference to the string from the first view controller.
Part of ViewController.m:
#interface ViewController ()
#property (copy,nonatomic) NSString *nameOfLabel;
#end
#implementation ViewController
- (IBAction)Switch:(id)sender {
NewView *new = [[NewView alloc] initWithNibName:nil bundle:nil];
new.secondLabel.text = self.nameOfLabel;
[self presentViewController: new animated:YES completion:NULL];
}
First of all please read about coding standards, it's not a good practice to:
Name variables like "new"
Name methods like "Switch"
Name UIViewController like "view" or "NewView"
Regarding logic:
This is all messed up here. What you actually do is you create viewController with nameOfLabel which is empty and is only changed on button press. I assume you press that button so it's changed. Then on switch action you create another viewController and present it. Then from inside that new viewController you create another new viewController which has empty nameOfLabel, get this empty value and put it inside secondLabel.
There are couple of ways you can do to change secondLabel:
Move nameOfLabel to model and read it from there when you want to change secondLabel,
Because your new viewController is child of viewController that keeps nameOfLabel you can access it by calling [[self presentingViewController] nameOfLabel] but make it property first,
Pass nameOfLabel through designated initializer.
Well, if you want a simple demonstration of access of a public ivar, the syntax is:
view->nameOfLabel;
^^
not dot-syntax:
view.nameOfLabel;
(dot-syntax just goes through accessor methods).
I've only seen a handful of warranted edge cases over the years; there's rarely, rarely ever a good reason to make an ivar public (also, protected is also rarely a good choice).
I try adding objects to NSMutableArray from another class (secondViewController) and then add it to my UITableView in my FirstViewController, but it returns null when I print it using NSLog. Here is my set up.
FirstViewController.h:
#interface FirstViewController : UIViewController <UITableViewDelegate,UITableViewDataSource>{
IBOutlet UITableView *mytableview;
NSMutableArray *mytableinfo;
}
#property (nonatomic,retain) IBOutlet UITableView *mytableview;
#property (retain) IBOutlet NSMutableArray *mytableinfo;
FirstViewController.m
#import "FirstViewController.h"
#import "SecondViewController.h"
#synthesize mytableinfo,mytableview;
-(IBAction)addShift:(id)sender{
SecondViewController *secondViewController = [[SecondViewController alloc]init];
[self presentModalViewController:secondViewController animated:YES];
}
- (void)viewDidLoad
{
mytableinfo = [[NSMutableArray alloc]init];
[super viewDidLoad];
}
SecondViewController.m
#import "SecondViewController.h"
#import "FirstViewController.h"
#implementation SecondViewController
#synthesize dateformatter,mydatepicker,startingTime;
-(IBAction)saveShift:(id)sender{
FirstViewController *firstViewController = [[FirstViewController alloc]init];
[firstViewController.mytableinfo addObject:#"Hello world"];
NSLog(#"%#",firstViewController.mytableinfo);
[self dismissModalViewControllerAnimated:YES];
}
My goal is to ultimately feed a mytableviewfrom mytableinfo. I'm not even sure if this is the best way to go about it. Any advice would be appreciated.
In SecondViewController, you are creating a FirstViewController with alloc init. At that point, mytableinfo on FirstViewController is nil because you don't allocate until viewDidLoad.
What loads SecondViewController? Because you're dismissing it modally. If it's FirstViewController, then when you alloc init first view controller, you're not calling the instance that presented it modally.
It's also not very MVC to have one view poke at another like that. It creates code that's couple at the view layer and modifying data at the view layer. It is better to create a model and have both views modifying that model.
How to create a NSMutable Array which can access from different view controllers
Another way to communicate between views is for one view to pass a delegate (a callback) to the other view. That allows the other view to not be coupled to the other view - it only knows about the protocol for the delegate.
What exactly does delegate do in xcode ios project?
There is a point that look strange to me in your "SecondViewController" you dissmiss it like it's a modal.
My Question is then... who started the modal presentation?
A "FirstViewController"? If it's the case, why are you creating a new one, on dismissing the second, the First that launched it will resume it's activity.
An other thing that I don't understand is that the designated initializer for a UIViewController is
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle
You can pass nil to both argument, if no nib need to be associated with.
And finaly, if you need to get back a NSMutableArray to a 1st ViewController (VC) from a 2nd VC that was modally presented by the 1st you can do this in the 2nd VC:
- (id)initWithMutableArray:(NSMutableArray *)theArray {
//... put standard init code here }
And make that the default initializer of your second VC. But this make sense only if 2nd VC absolutely need a mutable array.
And now for my curiosity because I don't understand this line
#property (retain) IBOutlet NSMutableArray *mytableinfo;
Why is this an IBOutlet? That look like a potential source of problem.
IBOutlet are usually pointers to UI elements in a xib file.
When populating a UITableView with an array that can be modified by multiple modal views during the course of your app, I find one of the best ways to do this is with NSUserDefaults. You can create an NSUserDefaults object for reference like this:
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
Then you can assign objects to each key in defaults, which is really just a plist (which is just a list of keys with objects associated with them.
So then, when you want to store the array in defaults, you can say:
[defaults setObject:mytableinfo forKey:#"tableInformationKey"];
Then, whenever you want to access that data, you can say:
NSMutableArray* tableInfoCopy = [defaults mutableArrayValueForKey:#"tableInformationKey"];
That will make you a copy of the array you have stored in NSUserDefaults (NSUserDefaults can be accessed from anywhere in your app), so then you can make changes to that mutable array you just made. Once you are done making changes, you can reassign it to NSUserDefaults like this:
[defaults setObject:tableInfoCopy forKey#"tableInformationKey"];
So when you populate your UITableView, in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
put something like:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Foobar"];
if (cell == nil) {
// No cell to reuse => create a new one
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Foobar"] autorelease];
// Initialize cell with some customization
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
cell.textLabel.textColor = [UIColor blackColor];
}
NSArray* arrayOne = [defaults objectForKey:#"tableInformationKey"];
NSString* title = [arrayTwo objectAtIndex:indexPath.row];
//this goes to the index in the array of whatever cell you are
// at, which will populate your table view with the contents of this array (assuming the array contains strings)
// Customize cell
cell.textLabel.font = [UIFont fontWithName:#"Helvetica" size:25];
return cell;
}
Use them the easiest way is to put the array in your AppDelegate
// populate appDelegate's array
AppDelegate *appDelegate = (myAppDelegate *) [[UIApplication sharedApplication] delegate];
[appDelegate.arrayMyTableInfo addObject:#"HelloWorld"];
Here is how you can do what I've suggested :
(This is part of your code updated)
This is in your secondView, this is one of many way to pass the array to your second view.
#synthesize array4Test;
- (id)initWithMutableArray:aMutableArray
{
self = [self initWithNibName:nil bundle:nil];
if (self)
{
self.array4Test = aMutableArray;
}
return self;
}
- (void)dealloc
{
// HERE clean up the property is set to retain.
self.array4Test = nil;
[super dealloc];
}
Here is the code for the firstView
-(IBAction)addShift:(id)sender{
SecondViewController *secondViewController = [[SecondViewController alloc] initWithMutableArray:self.mytableinfo];
[self presentModalViewController:secondViewController animated:YES];
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self.mytableview reloadData];
NSString *aString = [mytableinfo lastObject];
if (aString)
{
NSLog(#"This just came back from the second View\n%#", aString);
}
}
I have a PromoCodeViewController which is triggered using the following code:
#implementation Demo_WebServiceCallingUsingiOSAppDelegate
#synthesize window = _window,promoCodeController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.promoCodeController = [[PromoCodeViewController alloc] init];
[self.window addSubview:self.promoCodeController.view];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
The PromoCodeViewController contains the UITextField and I implement the UITextFieldDelegate for the PromoCodeViewController as shown:
#interface PromoCodeViewController : UIViewController<UITextFieldDelegate>
{
IBOutlet UITextField *promoCodeTextField;
}
#property (nonatomic,retain) IBOutlet UITextField *promoCodeTextField;
#end
I implement the textFieldShouldReturn method as shown:
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
return TRUE;
}
I have even setup the PromoCodeViewController to be the delegate for the UITextField events. When I start typing in the TextBox it throws "Program received signal. EXC_BAD_ACCESS". It happens when I type second character in the UITextField. What am I doing wrong?
UPDATE 1:
The error comes on the following section:
int main(int argc, char *argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([Demo_WebServiceCallingUsingiOSAppDelegate class]));
}
}
It looks as though you're missing an #synthesize statement for the promoCodeTextField property. Add the following to your Demo_WebServiceCallingUsingiOSAppDelegate class (which by the way, might benefit from renaming):
#synthesize promoCodeTextField = _promoCodeTextField;
Without the #synthesize statement, Xcode's Nib File Editor will directly set the instance variable instead of calling the accessor methods (since they don't exist); as a consequence the text field is never retained.
What object is the delegate of the textfield? Objects do not usually retain their delegates (since the delegate is often retaining a reference to the object, and retain-cycles lead to memory leaks).
My hunch is that your text field's delegate is defined and attached in your nib, but isn't being retained anywhere, so shortly after the nib is loaded the delegate is deallocated. As soon as the text field attempts to do anything with the delegate, it crashes.
If so, make sure something (usually the application delegate) is retaining a reference to whatever object is serving as the delegate of your text field.