How to pass Arrays to a UIPickerView from one class to another? - objective-c

Bah. I've pulled my hair out over this problem for the past couple days now, but I know I must be overlooking the obvious. I've made my PickerViewController(.h./m) and PickerViewAppDelegate(.h/.m) files and they run fine as a standalone program, but I would like to have the picker pop up after a procedureal event occurs in my "helloworld.m" file. I can get the picker to show up, but I cannot for the life of me figure out how to populate it so that it isn't blank. I THINK I've done everything right up until I try to pass my array to my pickerview object. What am I doing wrong?
PickerViewController.h
#import <UIKit/UIKit.h>
#interface PickerViewController : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate> {
IBOutlet UIPickerView *pickerView;
NSMutableArray *scrollerData;
}
#property (nonatomic, retain) IBOutlet UIPickerView *pickerView;
#property (nonatomic, retain) NSMutableArray *scrollerData;
-(void)setScrollerData:(NSMutableArray *)array;
#end
PickerViewController.m
#import "PickerViewController.h"
#implementation PickerViewController
#synthesize pickerView, scrollerData;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
self.pickerView.delegate = self;
self.pickerView.dataSource = self;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
- (void)dealloc {
// [arrayColors release];
[super dealloc];
}
-(void)setScrollerData:(NSMutableArray *)array
{
//[self.scrollerData arrayByAddingObjectsFromArray:array];
scrollerData = array;
}
#pragma mark -
#pragma mark Picker View Methods
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)thePickerView {
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)thePickerView numberOfRowsInComponent:(NSInteger)component {
return [scrollerData count];
}
- (NSString *)pickerView:(UIPickerView *)thePickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
return [scrollerData objectAtIndex:row];
}
- (void)pickerView:(UIPickerView *)thePickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
NSLog(#"Selected Number: %#. Index of selected numbers: %i", [scrollerData objectAtIndex:row], row);
}
PickerViewAppDelegate.h
#import <UIKit/UIKit.h>
#class PickerViewController;
#interface PickerViewAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
PickerViewController *pvController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#end
PickerViewAppDelegate.m
#import "PickerViewAppDelegate.h"
#import "PickerViewController.h"
#implementation PickerViewAppDelegate
#synthesize window;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
pvController = [[PickerViewController alloc] initWithNibName:#"PickerView" bundle:[NSBundle mainBundle]];
[window addSubview:pvController.view];
// Override point for customization after application launch
[window makeKeyAndVisible];
}
- (void)dealloc {
[pvController release];
[window release];
[super dealloc];
}
#end
Helloworld.m
...
UIView* view = [[CCDirector sharedDirector] openGLView];
UIPickerView *pickerView=[[UIPickerView alloc] init];
pickerView.frame=CGRectMake(100,100, 200, 200);
NSMutableArray *arrayNumbers = [[NSMutableArray alloc] init];
[arrayNumbers addObject:#"30"];
[arrayNumbers addObject:#"31"];
[arrayNumbers addObject:#"32"];
[arrayNumbers addObject:#"33"];
[arrayNumbers addObject:#"34"];
[arrayNumbers addObject:#"35"];
[arrayNumbers addObject:#"36"];
[pickerView setscrollerData: arrayNumbers];//Should I be calling pickerView here or something else?
[view addSubview: pickerView];
pickerView.hidden=NO;
...

You have overridden the setter method generated by #synthesize in PickerViewController, so you are no longer retaining it.
Then, you are calling setScrollerData on your pickerView (this should be giving you a warning or crashing since pickerView doesn't respond to that method).
You are not setting PickerViewController as the delegate or datasource of your picker view in helloworld.m.
I can't see where your hello world code fits in. It seems to be adding a new picker view rather than using the one from the xib of PickerViewController. You should be instantiating pickerviewcontroller from your hello world and adding its .view as a subview or presenting it as a modal view controller rather than setting up a new picker view. You can then pass your array to the instance of pickerviewcontroller. Note though that it is not standard to have a separate view controller for what is essentially a subview, though I don't have much knowledge of cocos2d so I don't know if this is normal when using that framework.

Well, i think you should just pass the array from HelloWorld class to PickerViewController class using property/synthesize.

Related

COCOA application crashed when trying to get the value from inactive dialog

I have created a main dialog (MainMenu.xib) and created two button on mainmenu.xib file and when click on each button, it will launch different xib file(say for button1 xib file is button1.xib and for button2 xib file is button2.xib file).
Now, My question I need the value of button1.xib file into button2.xib file.
I have tried the code
id appDelegate = (AppDelegate*)[[NSApplication sharedApplication] delegate] ;
this code always gives the delegate of active dialog.
Can you please tell me how to get the control or object of inactive dialog?
Thanks,
What you need is model object. Below is really simple approach how you should start. This model object should be stored in AppDelegate for non-document based app. Second window should not know about existence of any other window. The same applies for first window. It shouldn't know more that displaying/working with model.
Accessing model through delegate in fact accessing delegate like below is considered as really, really, really bad.
id model = [(AppDelegate*)[[NSApplication sharedApplication] delegate] model];
Simple example how you can implement model and monitor for changes
#import "AppDelegate.h"
#import "FirstWC.h"
#import "SecondWC.h"
#import "Model.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#property (nonatomic, strong) FirstWC *firstWC;
#property (nonatomic, strong) SecondWC *secondWC;
#property (nonatomic, strong) Model *model;
#end
#implementation AppDelegate
- (instancetype)init
{
self = [super init];
if (self) {
_model = [[Model alloc] init];
}
return self;
}
- (IBAction)changeColor:(id)sender
{
NSUInteger number = arc4random() % 4;
switch (number) {
case 0:
self.model.color = [NSColor redColor];
break;
case 1:
self.model.color = [NSColor blueColor];
break;
case 2:
self.model.color = [NSColor purpleColor];
break;
case 3:
self.model.color = [NSColor yellowColor];
break;
default:
break;
}
}
- (IBAction)showFirstWC:(id)sender
{
if (!_firstWC) {
_firstWC = [[FirstWC alloc] initWithModel:self.model];
}
[[_firstWC window] makeKeyAndOrderFront:self];
}
- (IBAction)showSecondWC:(id)sender
{
if (!_secondWC) {
_secondWC = [[SecondWC alloc] initWithModel:self.model];
}
[[_secondWC window] makeKeyAndOrderFront:self];
}
#end
Model:
#import <Cocoa/Cocoa.h>
#interface Model : NSObject
#property (nonatomic, strong) NSColor *color;
#end
#import "Model.h"
#implementation Model
- (instancetype)init
{
self = [super init];
if (self) {
_color = [NSColor blueColor];
}
return self;
}
#end
Window Controller:
#import "FirstWC.h"
#import "Model.h"
#interface FirstWC ()
#property (nonatomic, strong) Model *model;
#end
#implementation FirstWC
- (instancetype)initWithModel:(Model *)model
{
self = [super initWithWindowNibName:#"FirstWC"];
if (self) {
_model = model;
[self addObserver:self
forKeyPath:#"model.color"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:NULL];
}
return self;
}
- (void)windowDidLoad {
[super windowDidLoad];
self.window.backgroundColor = [self model].color;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
if ([keyPath isEqualToString:#"model.color"]) {
self.window.backgroundColor = self.model.color;
}
}
- (void)dealloc
{
[self removeObserver:self forKeyPath:#"model.color"];
}
#end
#import "SecondWC.h"
#interface SecondWC ()
#property (nonatomic, strong) Model *model;
#end
#implementation SecondWC
- (instancetype)initWithModel:(Model *)model
{
self = [super initWithWindowNibName:#"SecondWC"];
if (self) {
_model = model;
[self addObserver:self
forKeyPath:#"model.color"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:NULL];
}
return self;
}
- (void)windowDidLoad {
[super windowDidLoad];
self.window.backgroundColor = [self model].color;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
if ([keyPath isEqualToString:#"model.color"]) {
self.window.backgroundColor = self.model.color;
}
}
- (void)dealloc
{
[self removeObserver:self forKeyPath:#"model.color"];
}
#end
Add properties for both button1 and button2 in your controller, and a (weak) property for button2 in the button1 controller, and vice versa.
- (void)createButtons {
DlgController1 = [[Button1 alloc] initWithWindowNibName:#"Button1"];
DlgController2 = [[Button2 alloc] initWithWindowNibName:#"Button2"];
DlgController1.button2 = DlgController2;
DlgController2.button1 = DlgController1;
}
- (IBAction)Button1:(id)sender {
[DlgController1 showWindow:self];
[NSApp runModalForWindow:DlgController1.window];
[NSApp endSheet:DlgController1.window];
[DlgController1.window orderOut:self];
[DlgController1 close];
}
I have tried the code
id appDelegate = (AppDelegate*)[[NSApplication sharedApplication] delegate] ;
this code always gives the delegate of active dialog.
I'm not quite sure how this relates to the rest of your question, but the above issue suggests that you have an instance of your AppDelegate class in button1.xib and button2.xib. You should not.
There is only one application object in your app. It should have only one delegate. That instance is created in the MainMenu NIB and connected to the application's delegate outlet using the File's Owner placeholder's outlet. That should be the only instance of AppDelegate in your whole app.
If you also create an instance of AppDelegate in the other NIBs, then there will be multiple instances of that class once those NIBs are loaded, which will just confuse things. Also, if those instances are also connected to the application's delegate outlet, then they will replace the original delegate. That explains the symptom you described above where [[NSApplication sharedApplication] delegate] gives an object from the last NIB to load.
I'm not sure what button1.xib and button2.xib are supposed to contain. I'm guessing they are supposed to contain a window. In that case, you should write a custom subclass of NSWindowController to be the window controller for each window NIB. You would instantiate that class in the button's action method and provide it with whatever information it needs (possibly including a reference to the app delegate). That controller class would be responsible for loading the NIB. It would serve as the NIB's owner and would be represented in the NIB by the File's Owner placeholder. It's pretty common to make the window controller be the window's delegate, too. I recommend that you follow the advice of this blog post.

UIViewController in a UINavigationController not calling delegate method

In my Storyboard, I am using a UINavigationController with a navigation bar to present a view controller. This view controller, ViewController2, is pushed to the stack by tapping a UIBarButtonItem that I placed in the navigation bar. I made this connection in Interface Builder by dragging from the bar button to the ViewController2 scene and selecting "push" for the segue. To return back to the first view controller, I have an IBAction that calls the popViewControllerAnimated method. I'm using the delegate method to send data back to the first view controller but the string from ViewController2 is not being sent back to ViewController.
How can I pass the text entered in ViewController2 back to the first ViewController using the delegate method?
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#end
ViewController.m
#import "ViewController.h"
#import "ViewController2.h"
#interface ViewController () <UITableViewDelegate,UITableViewDataSource,Vc2Delegate>
#property (strong,nonatomic) NSArray *tableArray;
#property (weak,nonatomic) IBOutlet UITableView *listTableView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.listTableView setDelegate:self];
[self.listTableView setDataSource:self];
self.tableArray = #[#"item 1",#"item 2",#"item 3"];
ViewController2 *vc2 = [[ViewController2 alloc] init];
[vc2 setDelegate:self];
}
# pragma mark - TableView
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.tableArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ItemCell" forIndexPath:indexPath];
cell.textLabel.text = [self.tableArray objectAtIndex:indexPath.row];
return cell;
}
#pragma mark - Delegate Method
- (void)returnFromVc2:(NSString *)userString {
NSLog(#"delegate text is %#",userString);
}
#end
ViewController2.h
#import <UIKit/UIKit.h>
#protocol Vc2Delegate <NSObject>
- (void)returnFromVc2:(NSString *)userString;
#end
#interface ViewController2 : UIViewController
#property (weak,nonatomic) id <Vc2Delegate> delegate;
#end
ViewController2.m
#import "ViewController2.h"
#interface ViewController2 ()
#property (weak,nonatomic) IBOutlet UITextField *textField;
#end
#implementation ViewController2
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (IBAction)toPreviousVC:(id)sender {
NSLog(#"user text is: %#",self.textField.text);
[self.delegate returnFromVc2:self.textField.text];
[self.navigationController popViewControllerAnimated:YES];
}
#end
You set the delegate to a local variable that won't be the same instance as the one you push.
- (void)viewDidLoad {
....
ViewController2 *vc2 = [[ViewController2 alloc] init];
[vc2 setDelegate:self];
....
}
You should also make a habit of checking if your delegate can respond to the message sent.
- (IBAction)toPreviousVC:(id)sender {
NSLog(#"user text is: %#",self.textField.text);
if ( [self.delegate respondsToSelector(#selector(returnFromVc2:))] ) {
[self.delegate returnFromVc2:self.textField.text];
}
[self.navigationController popViewControllerAnimated:YES];
}

Objective-c update NSTextField at ControllerView init

#interface TestViewController : NSViewController
#property (nonatomic, retain) IBOutlet NSTextField *myLabel;
- (IBAction)sendMessage:(NSButton *)sender;
#end
#implementation TestViewController
#synthesize myLabel = _myLabel;
- (id)init{
self = [super init];
if(self){
[self updateLabel];
}
return self;
}
- (IBAction)sendMessage:(NSButton *)sender {
[self updateLabel];
NSLog(#"Message sent");
}
- (void) updateLabel{
NSLog(#"Update!! %#");
[self.myLabel setStringValue:#"random text"];
}
#end
I want to update an NSTextField when view is displayed, and i put my updateLabel at init in the log i see Update!! but the NSTextField it's not update with my text.
But when i press the button that calls the same updateLabel the NSTextField is updatet. Can someone help me to understand why it's not working as expected ?
I follow the suggestion of #rdelmar to use loadView. Thank you.
And here is how to implement it if anyone interested.
- (void)loadView
{
[super loadView];
[self updateLabel];
}

Passing value from one class to another, using #property

I have been pulling my hair out all afternoon trying to figure out why the following code will not work. All I am trying to do is pass a string, from one class to another.
In my FirstDetailViewController.h file I declare the NSString
#property(nonatomic, retain) NSString *infoForArray;
And then in my Grinding01_DetailViewController.m I try to set a value for the string
#import "Grinding01_DetailViewController.h"
#import "FirstDetailViewController.h"
#implementation Grinding01_DetailViewController
...
NSString *didLoadMessage = #"Grinding01 Loaded";
FirstDetailViewController *temp = [[FirstDetailViewController alloc] initWithNibName:#"FirstDetailView" bundle:nil];
temp.infoForArray = didLoadMessage;
[self.navigationController pushViewController:temp animated:YES];
}
When I output the infoForArray from the FirstDetailViewController.h it is null.
Any help would be appreciated, I think there's a simple step that I am missing, but I just can't see it.
EDIT: Here is the code from the FirstDetailViewController
FirstDetailViewController.h
#import <UIKit/UIKit.h>
#import "Protocols.h"
#interface FirstDetailViewController : UIViewController <SubstitutableDetailViewController> {
//for the output
IBOutlet UITextView *outputView;
UIToolbar *navigationBar;
NSMutableArray *logMessages;
}
#property (nonatomic, retain) IBOutlet UIToolbar *navigationBar;
//for incoming messages
#property(nonatomic, retain) NSString *infoForArray;
#end
FirstDetailViewController.m
#import "FirstDetailViewController.h"
#implementation FirstDetailViewController
#synthesize navigationBar, infoForArray;
-(void)viewDidLoad{
[super viewDidLoad];
//The log cannot be changed
outputView.editable = NO;
}
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidUnload {
[super viewDidUnload];
self.navigationBar = nil;
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:YES];
NSLog(#"message: %#", infoForArray);
outputView.text = infoForArray;
}
#pragma mark -
#pragma mark Managing the popover
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem {
// Add the popover button to the toolbar.
NSMutableArray *itemsArray = [navigationBar.items mutableCopy];
[itemsArray insertObject:barButtonItem atIndex:0];
[navigationBar setItems:itemsArray animated:NO];
[itemsArray release];
}
- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem {
// Remove the popover button from the toolbar.
NSMutableArray *itemsArray = [navigationBar.items mutableCopy];
[itemsArray removeObject:barButtonItem];
[navigationBar setItems:itemsArray animated:NO];
[itemsArray release];
}
#pragma mark -
#pragma mark Rotation support
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
#pragma mark -
#pragma mark Memory management
- (void)dealloc {
[navigationBar release];
[super dealloc];
}
#end
It sounds like the trouble area is in in FirstDetailViewController. I would suggest posting the code for that so we can see what's going on.
my guess is you are checking for infoForArray somewhere in the instantiation process of FirstDetailViewController, which occurs before you set temp.infoForArray = didLoadMessage.
Just for reference, if you check for infoForArray in viewDidLoad that will be too early. viewDidLoad is triggered when the view is put into memory. What you want is viewDidAppear, which you may have to add yourself

How to Change view(XIB) after imagePickerController:didFinishPickingMediaWithInfo?

I am new on iphone and objective-c development.
I want to know how i can change the view (XIB File) after the camera takes a picture.
Can anyone help me or share some code? I am searching for this since a week :(
After finishing the app, i am ready to share my project and/or make a tutorial.
Infos about my App: i want to scan barcodes and save the barcodes in my app.
For scanning barcodes iam using the ZBarSDK.
I hava a TabBarController, on the first Tab, i can open the camera.
After the scan process i want to jump to the second tab (another XIB File) and show the results.
Thanks for any help.
Here my code of the first tab (ScanCodeViewController):
.h
#import < UIKit/UIKit.h >
#class OutPutCodeViewController;
#interface ScanCodeViewController : UIViewController <ZBarReaderDelegate> {
IBOutlet UIImageView *img;
OutPutCodeViewController *output;
}
#property (nonatomic, retain) IBOutlet UIImageView *img;
#property (nonatomic, retain) OutPutCodeViewController *output;
- (IBAction) scanButton;
#end
.m
#import "ScanCodeViewController.h"
#implementation ScanCodeViewController
#synthesize img;
#synthesize output;
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[img release];
[super dealloc];
}
- (IBAction) scanButton {
NSLog(#"Scanbutton wurde geklickt!");
ZBarReaderViewController *reader = [ZBarReaderViewController new];
reader.readerDelegate = self;
ZBarImageScanner *scanner = reader.scanner;
[scanner setSymbology: ZBAR_I25 config: ZBAR_CFG_ENABLE to: 0];
[self presentModalViewController:reader animated: YES];
[reader release];
}
- (void) imagePickerController: (UIImagePickerController*) reader
didFinishPickingMediaWithInfo: (NSDictionary*) info
{
NSLog(#"Entered imagePickerController");
// ADD: get the decode results
id<NSFastEnumeration> results = [info objectForKey: ZBarReaderControllerResults];
ZBarSymbol *symbol = nil;
for(symbol in results) {
break;
}
img.image = [info objectForKey:UIImagePickerControllerOriginalImage];
[reader dismissModalViewControllerAnimated: YES];
//[self presentModalViewController:output animated:YES]; //by using this, app chrashes
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[picker dismissModalViewControllerAnimated: YES];
}
#end
And here the Secong Tab (OutPutCodeViewController)
.h
#import <UIKit/UIKit.h>
#interface OutPutCodeViewController : UIViewController {
IBOutlet UIImageView *resultImage;
IBOutlet UITextField *resultText;
}
#property (nonatomic, retain) IBOutlet UIImageView *resultImage;
#property (nonatomic, retain) IBOutlet UITextField *resultText;
#end
.m
#import "OutPutCodeViewController.h"
#implementation OutPutCodeViewController
#synthesize resultImage;
#synthesize resultText;
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[resultImage release];
[resultText release];
[super dealloc];
}
#end
Got it!
It is not possible to set more animate:YES.
Here is the sample and right code.
I hope it helps others.
- (void) imagePickerController: (UIImagePickerController*) reader
didFinishPickingMediaWithInfo: (NSDictionary*) info
{
// ADD: get the decode results
id<NSFastEnumeration> results =
[info objectForKey: ZBarReaderControllerResults];
ZBarSymbol *symbol = nil;
for(symbol in results)
break;
[reader dismissModalViewControllerAnimated: NO];
TableDetailViewController *tc = [[TableDetailViewController alloc] initWithNibName:#"TableDetailViewController" bundle:nil];
tc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:tc animated:YES];
[tc release];
}
brush51
In didFinishPickingMediaWithInfo you should call [self.tabBarController setSelectedIndex:1] to switch to the second tab.