Not able to access NSMutableArray from another class - ios

I've read through many posts here but I can't seem to make my array available in another class.
I want to access the array plusTransactions in CPPHistoryViewController (a table controller, in a container as a child of CPPSecondViewController) from class CPPSecondViewController.
CPPSecondViewController.h
#import <UIKit/UIKit.h>
#interface CPPSecondViewController : UIViewController <UIWebViewDelegate>
#property (weak, nonatomic) IBOutlet UIWebView *webView;
#property (weak, nonatomic) IBOutlet UISegmentedControl *segmentedController;
#property (weak, nonatomic) NSMutableArray *plustransactions;
#property (weak, nonatomic) NSMutableArray *campustransactions;
#property (weak, nonatomic) NSMutableArray *mealtransactions;
#end
CPPSecondViewController.m
#import "CPPSecondViewController.h"
#interface CPPSecondViewController ()
#implementation CPPSecondViewController
#end
#synthesize plustransactions = _plustransactions;
#synthesize campustransactions = _campustransactions;
#synthesize mealtransactions = _mealtransactions;
...
_plustransactions = newPlustransactions;
NSLog(#"%#", newPlustransactions);
NSLog(#"%#%lu", #"That's how many: ", (unsigned long)_plustransactions.count);
CPPHistoryViewController *historyView = [[CPPHistoryViewController alloc]init];
[historyView.tableView reloadData];
This is good, returns all of my array items and count is 7.
CPPHistoryViewController.h
#import <UIKit/UIKit.h>
#interface CPPHistoryViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource>
#end
CPPHistoryViewController.m
#import "CPPHistoryViewController.h"
#import "CPPSecondViewController.h"
#import "CPPPlusTransaction.h"
#import "CPPCampusTransaction.h"
#import "CPPMealTransaction.h"
#import "CPPHistoryCell.h"
#interface CPPHistoryViewController ()
#end
#implementation CPPHistoryViewController
...
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
CPPSecondViewController *secondView = [[CPPSecondViewController alloc] init];
NSMutableArray *plusTransactions = [[NSMutableArray alloc]init];
plusTransactions = secondView.plustransactions;
NSMutableArray *campusTransactions = [[NSMutableArray alloc]init];
campusTransactions = secondView.campustransactions;
NSMutableArray *mealTransactions = [[NSMutableArray alloc]init];
mealTransactions = secondView.mealtransactions;
NSLog(#"Table formatting called");
NSLog(#"%ld", (long)secondView.segmentedController.selectedSegmentIndex);
switch (secondView.segmentedController.selectedSegmentIndex) {
case 0:
NSLog(#"%#%lu", #"PlusTransactions", (unsigned long)plusTransactions.count);
return plusTransactions.count;
break;
case 1:
NSLog(#"%#%lu", #"CampusTransactions", (unsigned long)campusTransactions.count);
return campusTransactions.count;
break;
case 2:
NSLog(#"%#%lu", #"MealTransactions", (unsigned long)mealTransactions.count);
return mealTransactions.count;
break;
}
return 1;
}
...
#end
Here's where things get weird. Any array I call from here returns with a count of 0. Any ideas?

I assume what you want is to get the array data stored in CPPSecondViewController to be availalbe in CPPHistoryViewController. But as per the code you posted,
CPPHistoryViewController *historyView = [[CPPHistoryViewController alloc]init];
[historyView.tableView reloadData];
This just create new instance and the tableView inside the view is reloaded. But in cellForRowAtIndexPath, you are creating new instance of CPPSecondViewController, thats wrong.
What you can do is, simply pass the CPPSecondViewController instance before reloading tableView.
In CPPHistoryViewController.h, create a property for keeping secondView like this
#property (strong, nonatomic) CPPSecondViewController *secondView;
then, change your code in CPPSecondViewController like below:
CPPHistoryViewController *historyView = [[CPPHistoryViewController alloc]init];
historyView.secondView = self;
[historyView.tableView reloadData];
Also, remove alloc init statements from cellForRowAtIndexPath, just use secondView.plustransactions here.
Hope this helps!

CPPSecondViewController *secondView = [[CPPSecondViewController alloc] init];
Here you are creating a new object, So all values are nill.
Here you can only set values in to second view controller.
in your History class, you nedd to create a property of a second class they you can set value in to Second class
#property (nonatomic, retain) Secondclass* secondclass;
[secondClass setAry: ary];

CPPSecondViewController *secondView = [[CPPSecondViewController alloc] init];
in this code, the view controller is just init, the properties is all nil, it's a new view controller instance.
setup properties in init method, or access the second view's view property, to load view, to trigger the property initialize.
if you want reference the second view controller from history view controller, you can add a property in history view controller refer to second view controller.
in CPPHistoryViewController.h
#property (weak, nonatomic) CPPSecondViewController *secondViewController;
and set this property in your show code.
in CPPSecondViewController.m
_plustransactions = newPlustransactions;
NSLog(#"%#", newPlustransactions);
NSLog(#"%#%lu", #"That's how many: ", (unsigned long)_plustransactions.count);
CPPHistoryViewController *historyView = [[CPPHistoryViewController alloc]init];
historyView.secondViewController = self;
[historyView.tableView reloadData];

Related

Accessing properties from Object within NSMutableArray not working

I have the class LearnfestItem.h :
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface LearnfestItem : NSObject
#property (strong, nonatomic) NSString * itemId;
#property (strong, nonatomic) NSString * itemTitle;
#property (strong, nonatomic) NSString * itemDescription;
#property (strong, nonatomic) NSString * itemContent;
#property (strong, nonatomic) NSString * itemType;
#property (strong, nonatomic) UIImage * itemImage;
#property (strong, nonatomic) NSDate * itemRegistered;
-(id)initWithData:(NSDictionary *)data andImage:(UIImage *)image;
#end
& Object.m :
#import "LearnfestItem.h"
#import "Defaults.h"
#implementation LearnfestItem
-(id)init
{
self = [self initWithData:nil andImage:nil];
return self;
}
-(id)initWithData:(NSDictionary *)data andImage:(UIImage *)image
{
self = [super init];
self.itemId = data[ITEM_ID];
self.itemTitle = data[ITEM_TITLE];
self.itemDescription = data[ITEM_DESCRIPTION];
self.itemContent = data[ITEM_CONTENT];
self.itemType = data[ITEM_TYPE];
self.itemImage = image;
self.itemRegistered = data[ITEM_REGISTERED];
return self;
}
#end
In my UIViewController I have a UITableView that creates a NSMutableArray of LearnfestItems within the cellForRowAtIndexPath method:
LearnfestItem * createLearnfestItem = [[LearnfestItem alloc] initWithData:learnfestItemDictionary andImage:learnfestItemImage];
NSLog(#"Insert learnfest item with id: %# at index %li", createLearnfestItem.itemId, (long)row);
[self.learnfestItemObjects insertObject:createLearnfestItem atIndex:row];
On didSelectRowAtIndexPath I want to receive the LearnfestItem from the NSMutableArray I do this by calling:
self.selectedLearnfestItem = [self.learnfestItemObjects objectAtIndex:indexPath.row];
Then I want to send it to another view controller to present the data I do this in the prepareForSegue segement:
LearnfestItemViewController * learnfestVC = [segue destinationViewController];
NSLog(#"Sending learnfest item with id: %#", self.selectedLearnfestItem.itemId);
learnfestVC.item = self.selectedLearnfestItem;
When I try to access my LearnfestItem's properties within cellForRowAtIndexPath. All I get is null... and so forth in my other table view delegate methods.. Can anyone spot what i'm doing wrong? Thanks
Code you show is missing all error and validity checking. When using NSAssert() and item.length/item.count checks, you will know what's going on.
However, based on your code I'd suggest two things:
All objects which also have mutable version should use "copy" properties. Now you have "strong" pointer to data received via init method, but if you reset the originally given data variable to point elsewhere (e.g. reusing one data variable inside for loop to init multiple items), then... I don't know what your LearnfestItem item properties will point to.
Make sure your LearnfestItemViewController *item is a copy, too.
My guess is that everything is initialised correctly, but the data disappears afterwards.
For example:
#property (nonatomic, copy) NSString * itemId; // Safe
#property (nonatomic, strong) NSString * itemId; // Not safe
When your property class has mutable variations (e.g. NSString vs. NSMutableString vs. MyMutableString), copy is safer. Using strong will create a pointer to original data, which could have been a mutable instance and could be modified afterwards. Using strong will always point to original data, even after it has been changed.
Second part:
learnfestVC.item = self.selectedLearnfestItem;
Your LearnfestItemViewController contains some property related to LearnfestItem class. Make sure it's a copy, too. When using segues, the calling object quite often just disappears. Make sure your new controller has local copy of all needed data (or use a protocol delegate, but that's a longer discussion)
Adding error and data validity checking will make your task a lot easier. Instead of trying to figure out afterwards why something doesn't work, you'll get notifications when something isn't as you're expecting.
Here's quick and dirty "maintenance" for your code. What you should get out of this is some ideas what to check, where and how. In normal situations this is overkill, but now you have a mysterious problem and need to find it. It can be hard and monotonous work.
#import Foundation;
#import UIKit;
#interface LearnfestItem : NSObject
#property (copy, nonatomic) NSString *itemId;
#property (copy, nonatomic) NSString *itemTitle;
#property (copy, nonatomic) NSString *itemDescription;
#property (copy, nonatomic) NSString *itemContent;
#property (copy, nonatomic) NSString *itemType;
#property (strong, nonatomic) UIImage *itemImage;
#property (strong, nonatomic) NSDate *itemRegistered;
- (instancetype)initWithData:(NSDictionary *)data andImage:(UIImage *)image;
#end
Object.m :
#import "Defaults.h"
#import "LearnfestItem.h"
#implementation LearnfestItem
- (instancetype)init
{
self = [self initWithData:nil andImage:nil];
return self;
}
- (instancetype)initWithData:(NSDictionary *)data andImage:(UIImage *)image
{
NSAssert(data.length, #"My Assert: missing data");
NSAssert(image, #"My Assert: missing image");
if ((self = [super init]))
{
// TODO: nil ok, if doesn't exist?
_itemId = data[ITEM_ID];
_itemTitle = data[ITEM_TITLE];
_itemDescription = data[ITEM_DESCRIPTION];
_itemContent = data[ITEM_CONTENT];
_itemType = data[ITEM_TYPE];
_itemImage = image;
_itemRegistered = data[ITEM_REGISTERED];
}
return self;
}
#end
"(original text) In my UIViewController I have a UITableView that creates a NSMutableArray of LearnfestItems within the cellForRowAtIndexPath method:"
NSAssert(learnfestItemDictionary.count, #"My Assert: missing dict");
NSAssert(learnfestItemImage, #"My Assert: missing image");
LearnfestItem *createLearnfestItem = [[LearnfestItem alloc] initWithData:learnfestItemDictionary andImage:learnfestItemImage];
NSLog(#"Insert learnfest item with id: %# at index %#", createLearnfestItem.itemId, #(row));
NSAssert(createLearnfestItem, #"My Assert: missing item");
NSAssert(self.learnfestItemObjects.count > row, #"My Assert: learnfestItemObjects");
self.learnfestItemObjects[row] = createLearnfestItem;
"(original text) On didSelectRowAtIndexPath I want to receive the LearnfestItem from the NSMutableArray I do this by calling:"
NSAssert(self.learnfestItemObjects.count > indexPath.row, #"My Assert: learnfestItemObjects");
self.selectedLearnfestItem = self.learnfestItemObjects[indexPath.row];
"(original text) Then I want to send it to another view controller to present the data I do this in the prepareForSegue segment:"
LearnfestItemViewController *learnfestVC = (LearnfestItemViewController *)[segue destinationViewController];
NSLog(#"Sending learnfest item with id: %#", self.selectedLearnfestItem.itemId);
learnfestVC.item = self.selectedLearnfestItem;

Cannot display array on view load

I am trying to display the contents of an array by calling a method in a different class that loops through the array and appends a string. However it is not displaying anything when i segue to that view. I have added breakpoints to check if there is anything in the array and the data is definitely being stored inside.
Is there a reason why this is happening?
Portrait class where i want all the array contents to be displayed
portrait.h
#import <UIKit/UIKit.h>
#import "Brain.h"
#interface PortraitTape : UIViewController
#property (weak, nonatomic) IBOutlet UITextView *equationView;
#property (nonatomic,strong) Brain *brain;
#end
portrait.m
#import "PortraitTape.h"
#interface PortraitTape ()
#end
#implementation PortraitTape
#synthesize brain = _brain;
#synthesize equationView;
- (Brain *) brain{
if (!_brain)_brain =[[Brain alloc]init];
return _brain;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSString *tape;
tape = [self.brain gettape];
equationView.text = tape;
}
Brain.m class method that hashe array and data is being inserted into. This method is called in the portrait class.
-(NSString*) gettape {
NSMutableString *tape = [[NSMutableString alloc]init];
for(NSString * myStr in _equation) {
//tape = myStr;
[tape appendFormat:#"\n%#",myStr];
}
return tape;
}

Problems in adding object from one view to a mutableArray in another view

Hi everyone I have been building an app and have met some problems.
My app has two viewControllers. One is MenuViewController and another one is MainViewController.
I want to pass a string from MainViewController to a mutableArray in MenuViewController, but have no idea how.
Here are my codes:
<MenuViewController.h>
#import <UIKit/UIKit.h>
#interface MenuViewController : UITableViewController {
NSMutableArray *secondFavourite;
}
#property (nonatomic, strong) NSMutableArray *secondFavourite;
#end
.
<MenuViewController.m>
#import "MenuViewController.h"
#import "MainViewController.h"
#interface MenuViewController ()
#property (strong, nonatomic) NSArray *menu;
#end
#implementation MenuViewController
#synthesize menu;
#synthesize secondFavourite;
- (void)viewDidLoad
{
[super viewDidLoad];
self.secondFavourite = [[NSMutableArray alloc] init];
self.menu = self.secondFavourite;
}
.
<MainViewController.h>
#import <UIKit/UIKit.h>
#import <social/Social.h>
#interface MainViewController : UIViewController {
IBOutlet UIImageView *imagepost;
UILabel *predictionLabel;
}
- (IBAction)sampleSelector:(UIButton *)sender;
- (IBAction)showAllClick:(id)sender;
#property (nonatomic, retain) IBOutlet UILabel *predictionLabel;
#property (strong, nonatomic) NSArray *predictionArray;
#property (strong, nonatomic) UIButton *menuBtn;
#property (strong, nonatomic) NSMutableArray *fav;
#property (strong, nonatomic) IBOutlet UILabel *favLabel;
#property (strong, nonatomic) IBOutlet UITableView* tableView;
#property (nonatomic, strong) NSMutableArray *favourite;
#end
.
<MainViewController.m>
- (void)viewDidLoad
{
[super viewDidLoad];
self.predictionArray = [[NSArray alloc] initWithObjects:#"Hey gurl", nil];
}
//Add to favourite
- (void) addToFav {
self.favourite = [[NSMutableArray alloc] init];
[self.favourite addObject:self.predictionLabel.text];
[self.tableView reloadData];
NSLog(#"%#", self.favourite);
}
//add to favourite button action
- (IBAction)addToFavButton:(id)sender {
[self addToFav];
//pass data from favourite here to secondFacourite in MenuViewController (found on stack overflow)
MenuViewController *menuViewController = [[MenuViewController alloc]initWithNibName:#"MenuViewController" bundle:nil];
menuViewController.secondFavourite = [[NSMutableArray alloc]initWithArray:self.favourite];
[self.navigationController pushViewController:menuViewController animated:YES];
}
I used NSLog to check that the menuViewController.secondFavourite in MainViewController successfully added the string into the array, isn't the array the same array in MenuViewController? Why doesn't the menu.tableView update and show the new string added? I am very confused and I hope someone will help me out.
Thanks for reading this.
This has to do with the fact that your menu viewDidLoad is overwriting the value in these two lines:
self.secondFavourite = [[NSMutableArray alloc] init];
self.menu = self.secondFavourite;
That first line is setting your secondFavourite property to an empty NSMutableArray instance. And since viewDidLoad will be called only after the view has been loaded into memory (in this case, when you try to push the view controller onto the stack), your initial values in the secondFavourite property will be lost.
Instead, you should move that initialization code into the an init method.

Issue passing object to NSMutableArray in AppDelegate

I'm having trouble making a shopping cart sort-of concept in my app. I have my AppDelegate (named ST2AppDelegate) that contains an NSMutableArray called myCart. I want RecipeViewController.m to pass an NSString object to myCart, but every time I pass it the NSString and use NSLog to reveal the contents of the array, it is always empty.
Can anyone please tell me what I am doing wrong? I have worked on this code for days, and there is a line of code in which I don't understand at all what's going on (in the RecipeViewController.m, labeled as such).
Any help would be so appreciated... I'm just a beginner. Here are the relevant classes:
ST2AppDelegate.h:
#import <UIKit/UIKit.h>
#interface ST2AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) NSMutableArray* myCart;
- (void)addToCart:(NSString*)item;
- (void)readCartContents;
#end
ST2AppDelegate.m:
#import "ST2AppDelegate.h"
#implementation ST2AppDelegate
#synthesize myCart;
// all the 'applicationDid...' methods...
- (void)addToCart:(NSString *)item
{
[self.myCart addObject:item];
}
- (void)readCartContents
{
NSLog(#"Contents of cart: ");
int count = [myCart count];
for (int i = 0; i < count; i++)
{
NSLog(#"%#", myCart[count]);
}
}
#end
RecipeDetailViewController.h:
#import <UIKit/UIKit.h>
#import "ST2AppDelegate.h"
#interface RecipeDetailViewController : UIViewController
#property (nonatomic, strong) IBOutlet UILabel* recipeLabel;
#property (nonatomic, strong) NSString* recipeName;
#property (nonatomic, strong) IBOutlet UIButton* orderNowButton;
- (IBAction)orderNowButtonPress:(id)sender;
#end
RecipeDetailViewController.m:
#import "RecipeDetailViewController.h"
#implementation RecipeDetailViewController
#synthesize recipeName;
#synthesize orderNowButton;
// irrelevant methods...
- (IBAction)orderNowButtonPress:(id)sender
{
// alter selected state
[orderNowButton setSelected:YES];
NSString* addedToCartString = [NSString stringWithFormat:#"%# added to cart!",recipeName];
[orderNowButton setTitle:addedToCartString forState:UIControlStateSelected];
// show an alert
NSString* addedToCartAlertMessage = [NSString stringWithFormat:#"%# has been added to your cart.", recipeName];
UIAlertView* addedToCartAlert = [[UIAlertView alloc] initWithTitle:#"Cart Updated" message:addedToCartAlertMessage delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[addedToCartAlert show];
// add to cart (I don't understand this, but it works)
[((ST2AppDelegate*)[UIApplication sharedApplication].delegate) addToCart:recipeName];
// read cart contents
[((ST2AppDelegate*)[UIApplication sharedApplication].delegate) readCartContents];
}
#end
You need to initialize myCart when your application launches:
self.myCart = [[NSMutableArray alloc] init];
otherwise you are just attempting to add objects to a nil object which while it won't throw an exception because of the way objective-c handles nil objects it will not function as expected until you initialize it.
Do you ever initalize the shopping cart variable?
Try doing lazy instantiation.
-(NSMutableArray *) myCart{
if (!_myCart){
_myCart = [[NSMutableArray alloc] init];
}
return _myCart;
}
This way you will know it will always get allocated. Basically, this method makes it so that whenever someone calls your classes version of the object it checks to see if that object has been allocated and then allocates it if it has not. It's a common paradigm that you should employ with most of your objects.
This method should go in the app delegate (where the object was declared).

using protocol app getting crashed ipad

I have application where i have two view controllers my first view and second view controller is in uipopovercontroller. i want value of second view controller in first view for that i have created protocol. here is my code.
#import
#import "SearchPopoverController.h"
#import "AppDelegate.h"
#interface ViewController : UIViewController<PassSearchValueDelegate>{
AppDelegate *appDelegate;
SearchPopoverController *popSearch;
IBOutlet UILabel *lblAdd;
}
-(IBAction)showpop:(id)sender;
#end
#import "ViewController.h"
// my ViewController.m file code
-(void) getLocationList:(NSString *)strSearch{
lblAdd.text = strSearch;
}
-(IBAction)showpop:(id)sender{
if(![appDelegate.delObjSearchPopoverCon isPopoverVisible]){
SearchPopoverController *popser = [[SearchPopoverController alloc] init];
popSearch = popser;
[popSearch setDelegate:self];
appDelegate.delObjSearchPopoverCon = [[UIPopoverController alloc] initWithContentViewController:popSearch] ;
[appDelegate.delObjSearchPopoverCon setPopoverContentSize:CGSizeMake(400 , 150)];
[appDelegate.delObjSearchPopoverCon presentPopoverFromRect:CGRectMake(0, 0, 1, 1) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
}
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#protocol PassSearchValueDelegate
#required
-(void) getLocationList:(NSString *)strSearch;
#end
#interface SearchPopoverController : UIViewController <UITextFieldDelegate>{
AppDelegate *appDelegate;
IBOutlet UITextField *txtSearchAdd;
IBOutlet UILabel *lblSearchAdd;
id<PassSearchValueDelegate> _delegate;
}
#property (retain) id _delegate;
#end
// my SearchPopoverController.m file code
-(IBAction)btnDoneSearch_clicked:(id)sender{
NSString *strAdd = [txtSearchAdd.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
strAdd = [strAdd stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[appDelegate.delObjSearchPopoverCon dismissPopoverAnimated:YES];
if (strAdd != nil || strAdd.length != 0) {
[_delegate getLocationList:strAdd];
}
}
i am getting warning at this line.
[popSearch setDelegate:self];
and app getting crashed very next line.
Please help me for this. Any help will be appreciated.
id<PassSearchValueDelegate> _delegate;
// ...
#property (retain) id _delegate;
Your property should be named just delegate and maybe synthesized to use the _delegate instance variable. You should also specify the protocol on the property type.
Additionally, delegates should be assign (or weak under ARC) properties.
rename _delegate to delegate
You will need to change
#property (retain) id delegate;
to
#property (assign) id<PassSearchValueDelegate> delegate;
Also in PassSearchValueDelegate.m add
#implementation PassSearchValueDelegate //After this
#synthesize delegate; //add this

Resources