Obj-C globally use NSArray - iphone

I have a ViewController that prompts the FBFriendPickerViewController in which I, at selection, am returned with an NSArray containing the selection. Now I want to prompt and show a new ViewController using this selection information. I am new to Objective C, but I guess the solution is pretty simple. Here is my proposal:
ViewController2.h
- (id)initWithStyle:(UITableViewStyle)style andSelection:(NSArray *)selection;
#property (strong, nonatomic) NSArray *selectedParticipants;
ViewController2.m
- (id)initWithStyle:(UITableViewStyle)style andSelection:(NSArray *)selection {
self = [super initWithStyle:style];
if (self) {
self.title = NSLocalizedString(#"Split Bill", nil);
self.tableView.backgroundColor = [UIColor wuffBackgroundColor];
self.selectedParticipants = selection;
}
return self;
}
- (void)setSelectedParticipants:(NSArray *)selectedParticipants {
NSLog(#"setSelectedParticipants (%d)", [selectedParticipants count]);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"%d rowsInSection", [self.selectedParticipants count]);
return [self.selectedParticipants count];
}
ViewController1.m
- (void)actionSheet:(UIActionSheet *)actionSheet willDismissWithButtonIndex:(NSInteger)buttonIndex {
if (buttonIndex == 2) {
[[self friendPickerController] presentModallyFromViewController:self animated:YES handler:^(FBViewController *sender, BOOL donePressed) {
if (donePressed) {
ViewController2 *vc = [[ViewController2 alloc] initWithStyle:UITableViewStyleGrouped
andSelection:[self.friendPickerController selection]];
[self.navigationController pushViewController:vc animated:YES];
}
//[[self friendPickerController] clearSelection];
}
];
}
}
It seems, however, that the first setSelectedParticipants-log returns the correct amount of selected friends, but the numberOfRowsInSection-log returns 0.
Why is this?
Thanks in advance!

The problem here is in your setter:
- (void)setSelectedParticipants:(NSArray *)selectedParticipants {
NSLog(#"setSelectedParticipants (%d)", [selectedParticipants count]);
}
You will notice that you never actually set the value for the instance variable backing the property, in this case, the default is _selectedParticipants. So, to fix, simply add the following line to your setter:
_selectedParticipants = selectedParticipants;
And you should be good to go.

Remove this function from your code
- (void)setSelectedParticipants:(NSArray *)selectedParticipants {
NSLog(#"setSelectedParticipants (%d)", [selectedParticipants count]);
}
You are already set the selectedParticipants in init method

Related

Trouble with the UITextField inputview property pulling up a custom UIPickerView

I have been having trouble pulling up a custom UIPickerView from the textfield's inputview property. I have been working on this for awhile, did some research, and tried to put together a separate project based on Apple's UICatalog example.
However, whenever I tap inside the textfield all I get is a black screen that pops up in place of the picker view. Im sure I've overlooked something but I have been looking for days any help would be appreciated.
Keep in mind this was my test project to see if I could add this functionality to my other app and that a lot of the code I tried to copy from the UICatalog app. Sorry if anything doesn't make sense and please feel free to ask any questions you may have. Thank you.
// ViewController.h
// TestPicker
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITextFieldDelegate,UIPickerViewDelegate,UIPickerViewDataSource>{
UIPickerView *picker;
//The picker view the textfield responds to.
IBOutlet UITextField *myText;
//The textfield which has the input view of a picker.
NSArray *testArray;
//The array which values are loaded into the picker.
}
#end
// ViewController.m
// TestPicker
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
picker.delegate=self;
picker.dataSource=self;
myText.delegate=self;
[self createPicker];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
myText = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
else {
return YES;
}
}
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
picker = [[UIPickerView alloc] initWithFrame:CGRectZero];
myText.inputView=picker;
return YES;
}
-(void)textFieldDidBeginEditing:(UITextField *)textField{
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
NSString *returnStr = #"";
if (pickerView == picker)
{
if (component == 0)
{
returnStr = [testArray objectAtIndex:row];
}
else
{
returnStr = [[NSNumber numberWithInt:row] stringValue];
}
}
return returnStr;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [testArray count];
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
- (void)createPicker
{
testArray = [NSArray arrayWithObjects:
#"John Appleseed", #"Chris Armstrong", #"Serena Auroux",
#"Susan Bean", #"Luis Becerra", #"Kate Bell", #"Alain Briere",
nil];
picker = [[UIPickerView alloc] initWithFrame:CGRectZero];
picker.showsSelectionIndicator = YES; // note this is default to NO
picker.delegate = self;
picker.dataSource = self;
}
#end
The problem is in this method:
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
picker = [[UIPickerView alloc] initWithFrame:CGRectZero];
myText.inputView=picker;
return YES;
}
You already created picker in your createPicker method, called from viewDidLoad, so this creates another instance (this instance won't have the delegate or data source set to self, since these were set on the first instance you created). If you just delete the first line of this method, it should work.
Two other comments on your code. The first 2 lines in the viewDidLoad method aren't doing anything since you haven't created picker yet -- they should be deleted. You also need to implement the pickerView:didSelectRow:inComponent: method in order to get the selected value of your picker into the text field.

iphone delegate protocol can't save object

ok, i was trying to understand this post about best way to transfer data from one view controller to other.
the thing is, if i want to set an attr of the object its works like a champ. If i try to set the entire object, it doesnt do it.
my code is:
#protocol AppDelegateProtocol
- (Lote*) theLoteAppObject;
#end
on AppDelegate:
#interface AgroferiaAppDelegate : NSObject <UIApplicationDelegate, AppDelegateProtocol> {
Lote *theLoteAppObject;
}
#property (nonatomic, retain) Lote *theLoteAppObject;
#end
...
...
- (id) init;
{
self.theLoteAppObject = [[Lote alloc] init];
[theLoteAppObject release];
return [super init];
}
the class where i get the problem (UIViewcontroller):
-(void)tableView:(UITableView *) aTableView didSelectRowAtIndexPath:(NSIndexPath *) indexPax{
...
NSArray *lotes = [[self.evento lotesStore]allLotes] ;
Lote* theDataObject = [self theLoteAppObject];
theDataObject._id = [[lotes objectAtIndex:[indexPax row]]_id];
[[self navigationController]pushViewController:lotesOpViewController animated:YES];
}
- (Lote*) theLoteAppObject;{
id<AppDelegateProtocol> theDelegate = (id<AppDelegateProtocol>) [UIApplication sharedApplication].delegate;
Lote* theDataObject;
theDataObject = (Lote*) theDelegate.theLoteAppObject;
return theDataObject;
}
so that works, but if i want to do the followimg,
theDataObject = [lotes objectAtIndex:[indexPax row]];
it does not save the object on theDataObject.
is this a problem of bad memory managment?
edit: is it theDataObject a reference from appDelegate ?? or here is the problem?
try something like this:
if([indexPax row] < [lotes count])
{
Lotes * dataObjectToCopy = [lotes objectAtIndex: [indexPax row]];
if(dataObjectToCopy)
{
theDataObject = [dataObjectToCopy copy];
}
}
This creates a separate, retained copy of your Lote object. Make sure to release it when you're finished with it (if you're not using ARC).

NSArray losing data in objective-c, Could someone explain why?

I have an nsarray that when I NSLog it from one of my methods (inside WorkOutList.m) I can see its contents, but when I try to look inside it from a different method inside WorkOutList.m it seems to be empty. I am aware that my memory management needs some work, could anyone help explain whats happening here?
I am using popViewControllerAnimated:YES to return the view from a tableView back to a view controller, but just before I do that I set my array in a method inside WorkOutList. When I NSLog that array from that same method I am returned results, however when i NSLog it from else where it is returned empty.
I have been told that it might be the viewDidLoad method where the array is init, but that the other array in that method customWorkouts still retains its data. So i dunno, any explanation would be really helpful. I want this to work, but I also really want to understand it so I can get on with coding correctly.
Thanks so much!
WorkOutList.h
#import <UIKit/UIKit.h>
#interface WorkOutList : UIViewController {
NSManagedObjectContext *managedObjectContext;
NSMutableArray *customWorkouts;
NSArray *passedWorkout;
}
#property(nonatomic, retain)NSManagedObjectContext *managedObjectContext;
#property(nonatomic, retain)NSMutableArray *customWorkouts;
#property(nonatomic, retain)NSArray *passedWorkout;
-(IBAction)customWorkouts:(id)sender;
-(void)passWorkoutBack:(NSArray *)workout;
#end
WorkOutList.m
#implementation WorkOutList
#synthesize managedObjectContext, customWorkouts, passedWorkout;
- (void)viewDidLoad {
[self setupContext];
NSLog(#"View Did Load");
customWorkouts = [[NSMutableArray alloc] init];
passedWorkout = [[NSArray alloc] init];
[super viewDidLoad];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self fetchWorkoutList];
NSLog(#"View will Appear");
NSLog(#"Array from View Will Appear : %#", passedWorkout);
}
-(IBAction)customWorkouts:(id)sender{
CoCoachAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
SelectedWorkout *selectedWorkout = [[SelectedWorkout alloc] initWithStyle:UITableViewStyleGrouped];
[selectedWorkout recieveNeededData:customWorkouts];
[appDelegate.practiceNavController pushViewController:selectedWorkout animated:YES];
[selectedWorkout release];
}
-(void)passWorkoutBack:(NSArray *)workout{
passedWorkout = workout;
[passedWorkout retain];
}
- (void)dealloc {
[super dealloc];
}
SelectedWorkout.h
#import <UIKit/UIKit.h>
#interface SelectedWorkout : UITableViewController {
NSMutableArray *workoutListForTable;
}
#property(nonatomic,retain)NSMutableArray *workoutListForTable;
-(void)recieveNeededData:(NSMutableArray *)workoutList;
#end
SelectedWorkout.m(aside from all the stuff to set up the tableView)
#implementation SelectedWorkout
#synthesize workoutListForTable;
-(void)recieveNeededData:(NSMutableArray *)workoutList{
if (workoutListForTable != workoutList) {
workoutListForTable = workoutList;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
CoCoachAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
WorkOutList *workoutListView = [[WorkOutList alloc]init];
[workoutListView passWorkoutBack:[workoutListForTable objectAtIndex:indexPath.row]];
[appDelegate.practiceNavController popViewControllerAnimated:YES];
}
- (void)dealloc {
[workoutListForTable release];
[super dealloc];
}
NSLog(#"other table : %#", workoutListForTable);
[workoutListForTable retain];
}
In this line:
passedWorkout = [[NSArray alloc] init];
You're creating an immutable array with nothing in it. What do you want it to contain?
It looks to me that although you are initializing your array with or so I assume, since on the other line you are only allocating an empty array.
[self fetchWorkoutList]
You are resetting it here every time:
[workoutListView passWorkoutBack:[workoutListForTable objectAtIndex:indexPath.row]];
As a note here:
-(void)passWorkoutBack:(NSArray *)workout{
passedWorkout = workout;
[passedWorkout retain];
}
You have the property passedWorkout as retain already, however you need to call it on self
-(void)passWorkoutBack:(NSArray *)workout{
self.passedWorkout = workout;
}

iPhone TableView Data Into 2 Sections

I am trying to get a tableview to split data i have in an array into sections...
I'm pretty new to this but below is my code snippet
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(section == 0)
{
contentArray = [[NSArray arrayWithObjects:#"Send SMS", #"Reports", nil] retain];
}
if(section == 1)
{
contentArray = [[NSArray arrayWithObjects:#"Accounts", nil] retain];
}
return [contentArray count];
}
I have split the data successfully into the 2 sections but when populating the rows It just repeats the first content array in both sections.
Can any one help...
Thanks
First things first, you have a leak in the code you presented. Remove the two calls to retain.
Second, you are in the classic problem of having multiple switches/if..else chains based on the same information. This screams for an OO solution.
First create a TableSection class:
#interface TableSection : NSObject
{ }
#property (nonatomic, copy) NSString* header;
#property (nonatomic, copy) NSArray* rows;
- (NSInteger)numberOfRows;
- (UITableViewCell*)cellInTableView: (UITableView*)tableView forRow: (NSInteger)row;
#end
#implementation TableSection
#synthesize header;
#synthesize rows;
- (void)dealloc {
[header release];
[rows release];
[super dealloc];
}
- (NSInteger)numberOfRows {
return rows.count;
}
- (UITableViewCell*)cellInTableView: (UITableView*)tableView forRow: (NSInteger)row {
// create/reuse, setup and return a UITableViewCell
}
#end
Now in your TableViewController
#interface MyViewController : UITableViewController
{ }
#property (nonatomic, retain) NSArray* tableSections;
#end
#implementation MyViewController
- (void)dealloc {
[tableSections release];
[super dealloc];
}
- (void)viewDidLoad {
TableSection* section1 = [[TableSection alloc] init];
[section1 setRows: [NSArray arrayWithObjects: #"Send SMS", #"Reports", nil]];
TableSectlion* section2 = [[TableSection alloc] init];
[section2 setRows: [NSArray arrayWithObjects: #"Accounts", nil]];
[self setTableSections: [NSArray arrayWithObjects: section1, section2, nil]];
[section2 release];
[section1 release];
}
- (void)viewDidUnload {
[self setTableSections: nil];
}
#pragma mark UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView: (UITableView*)tableView {
return self.tableSections.count;
}
- (NSInteger)tableView: (UITableView*)tableView numberOfRowsInSection: (NSInteger)section {
return [[self.tableSections objectAtIndex: section] numberOfRows];
}
- (UITableViewCell*)tableView: (UITableView*)tableView cellForRowAtIndexPath: (NSIndexPath*)indexPath {
return [[self.tableSections objectAtIndex: indexPath.section] cellInTableView: tableView forRow: indexPath.row];
}
- (NSString*)tableView: (UITableView*)tableView titleForHeaderInSection: (NSInteger)section {
return [[self.tableSections objectAtIndex: section] header];
}
#end
don't switch (and leak) your content data in one of the tableview datasource or delegate methods. tableView:numberOfRowsInSection: can be called an arbitrary number of times. With your code you are relying on a particular order in which those methods are called.
You should have a separate array for each section (or one array that holds the two section arrays)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(section == 0) {
return [section0Array count];
}
if(section == 1) {
return [section1Array count];
}
return 0;
}
And you could create those arrays in viewDidLoad:
section0Array = [[NSArray arrayWithObjects:#"Send SMS", #"Reports", nil] retain];
section1Array = [[NSArray arrayWithObjects:#"Accounts", nil] retain];
i suppose you should put the code in cellForRowAtIndexPath because where you are writting there we generally add the count of rows in each section
You need to make sure that the (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method is also returning the correct cells based on your splitting of the content array. You can do the similar check in the method something like
switch(indexPath.section)
{
case 0: //First Section
switch(indexPath.row)
{
case 0: //Setup the cell Send SMS
break;
case 1: //Setup the cell Reports
break;
}
}

NSIndexPath: message sent to deallocated instance

Any help you can offer would be appreciated.
I have a app that has a tableView, detailView, flipView, and moreDetail View. It is fine moving through the transitions until the 26th element. The app crashes when I hit buttons that navigate to the flip and moreDetailView.
I am given the error Msg: [NSIndexPath row] message sent to deallocated instance.
I think I may be calling the indexPath too many times, but why does everything work well up until the 25th element and then stop working? How did the NSIndexPath get deallocated? I never deallocated it.
If you know, please help. Thank you!!!
Xcode says the problem is here:
#implementation produceView aka *detailView*
- (IBAction)showInfo {
FlippedProduceView *fView = [[FlippedProduceView alloc]initWithIndexPath:index];
fView.flipDelegate = self;
fView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:fView animated:YES];
[fView release];
}
- (IBAction) buttonPushed:(id)sender
{
picView *pictureView = [[picView alloc]initWithIndexPath:index];
pictureView.picDelegate = self;
pictureView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:pictureView animated:YES];
[pictureView release];
}
-(id)initWithIndexPath:(NSIndexPath *)myIndexPath {
if (self == [super init]) {
path = myIndexPath;
}
return self;
}
#implementation picView aka *moreDetailView*
- (void)viewDidLoad {
RipeGuideAppDelegate *AppDelegate = (RipeGuideAppDelegate *)[[UIApplication sharedApplication] delegate];
self.picViewArray = AppDelegate.arrayProduceInfo;
NSMutableDictionary *dictionary = [picViewArray objectAtIndex:path.row];
}
#implementation FlippedProduceView aka *flipView*
- (id)initWithIndexPath:(NSIndexPath *)myIndexPath {
if (self == [super init]) {
indexes = myIndexPath;
}
return self;
}
- (void)viewDidLoad {
RipeGuideAppDelegate *AppDelegate = (RipeGuideAppDelegate *)[[UIApplication sharedApplication] delegate];
self.flipViewArray = AppDelegate.arrayProduceInfo;
NSMutableDictionary *dictionary = [flipViewArray objectAtIndex:indexes.row];
}
You should use properties (#property (retain) NSIndexPath *path;) instead of instance variables, so then when you do self.path = myIndexPath then it raises the retain count so it won't be deallocated when IndexPath is autoreleased.