Adding object to NSMutableArray in another xib - iphone

Im trying to add an object to a NSMutableArray in another xib. But seems isnt working. What im doing wrong?
Thanks!
-(void) buy {
CartViewController *carrinho = [[CartViewController alloc] initWithNibName:#"CartViewController" bundle:[NSBundle mainBundle]];
carrinho.produtoCodigo = [[NSMutableArray alloc]init];
[carrinho.produtoCodigo addObject:#"aa"];
[carrinho release];
NSLog(#"did");
}

Your code looks fine so far. Make sure the connections in InterfaceBuilder and the File's owner in the XIB is set correctly.

Ok, several things. First you don't need to pass in [NSBundle mainBundle]. nil works fine if you want the main bundle. Second issue is, produtoCodigo should be a property set to retain and as such you should pass in an autoreleased NSMutableArray i.e. [NSMutableArray array].
Thirdly, I would question why you would want to do this. It seems like a bad design. Ideally the mutable array should be an internal ivar in CartViewController. You should then have a method on CartViewController to handle the item. You should not care about how it is stored internally, only that you want to add an object to the controller.
If you want to pass in multiple objects you should have a method that takes an array of objects and pass that in.
Now finally, nibs don't really hold arrays, the class does. As such it shouldn't be an issue with your nib. The issue should therefore be with the class. Where are you checking whether the array is being updated and finding that it isn't?

you declare and create carrinho as a view controller, which should allocate and init the carrinho.produtoCodigo as well, if you have it synthesized. Then you alloc it again, which may be a memory leak. After adding the aa, you release it. Therefore, overall, you haven't accomplished anything. That mutable array comes into being, is modified, and then destroyed.
You mention "another xib" and from the name CartController and method name "buy" it sounds like you want to update a shopping cart that is being held by some other class. Therefore, the view or class with the cart (and mutable array) needs to be modified. It's like if you and a friend go shopping, and you delegate the job of managing the cart to him. He is the delegate, and only he can put stuff in the cart. Just because you want to buy something, you have to give it to him first so that he can put it in the cart. Right now, your code is like you grab something off the rack, but then put it back on the rack. It never makes it into the cart.
What you want to do is create a shopping protocol with a message addToCart which is what this code would instead do. It would send the message to the delegate to add the item to the cart. The other xib code has a method -(void)addToCart:(id)item; which is what is invoked when this code chunk does to call to the delegate. Look up protocols and delegates; they are simple to create, and the only way to get multiple controllers talking to one another.

Maybe you inserted this below code in the second XIB:
-(void) viewDidLoad {
produtoCodigo = [[NSMutableArray alloc] init];
}
because if you make allocate an array again, the previous objects in it will be removed.

Related

iPhone How To Save View States

I have been developing iphone applications for around 3months now and theres a few things that stump me and i don't really have an idea how to work round them.
I have a navigation controller controlling the views in my application however every screen that is loaded, used then pushed back loses all the information as it seems to be reinstantiated... I believe this is a possible memory management issue?
But how to i create an app that navigates and retains all information in its views until the application is closed.
Thanks :)
Possible you didn't keep a reference to the view controller, the issue is for UIVIewController not to be released.
Make the view controller an ivar you will instanciate only one time when you push it on stack.
// in .h
MyViewController *mVC;
// in .m
// maybe when the user selects a row in a tableview
if(mVC == nil) {
// first time use, alloc/init
mVC = [[MyViewController ....];
}
// then push on the stack
[self.navigationController ....];
Of course don't forget to release it later.
In this part:
MyViewController *myViewController=[MyViewController alloc] initWithNibName:#"myView" bundle:nil];
[[self navigationController] pushViewController:myViewController animated:YES];
[myViewController release];
You will probably have something like this... Instead, make your myViewController a class's property so you have a reference to it. And drop the [myViewController release]; statement.
Possibly your app is receiving a didReceiveMemoryWarning.
In such cases, when the super class is called, the framework does memory cleaning by unloading all the views that are not currently displayed. This could explain the behavior you are seeing.
To check it further, override didReceiveMemoryWarning in one of your view controllers or applicationDidReceiveMemoryWarning in your app delegate, and put a breakpoint in it. Don't forget to call [super...] appropriately, otherwise pretty soon your app will be killed. What you should see in this way is that the views do not disappear before hitting the breakpoint, and do disappear after that.
If the hypothesis is correct, you should find a way to save the state of your view in viewDidUnload and restore it in viewDidLoad. Look also at didReceiveMemoryWarning reference.
Try to save data in NSUserDefaults it its small or use plist or it its too small like 5-10 objects save in in some variable in appDelegate, and if its too large use sqlite and for saving something like images of files like xml use Document directory
The UINavigationController works like a stack: you push and pop UIViewControllers on it. That means when a UIViewController get popped, it will have its retain count decremented by 1, and if no other object holds a reference to it, it will be deallocated. You can avoid the UIViewControllers getting dealloced by keeping a reference to them yourself by calling -retain on the objects, for instance in your appDelegate.
You can use NSUserDefaults to save the states of the UIControls in the view.
So whenever u r loading a view, set the values to the controls so that it looks like it resume from the place where we left.

several questions about obj-c (delegate, viewController, simulator)

i had several questions about objective-c, could you help me understand it? Here they are :
why do we use sometimes :
self.myView.delegate = self; ?
There is the same thing with the Ipad and Splitview : why do we use the delegate explicitly like this :
uisplitviewController *svc = ...
svc.delegate = pvc.otherViewController;
For now, i understand the "appDelegate", but what about this delegate method?
2.I saw several times the use of another "viewController" as below, instead of "allocating" directly the "mainViewControler", why do we use this intermediate?
MainViewController *viewController = [[MainViewController alloc] initWithNibName:#"MainView" bundle:nil];
self.mainViewController = viewController;
[viewController release];
3.Following some tutorials from appsmuck.com, i saw that they use :
"(void)loadFlipsideViewController "
but no "loadView", so, can we replace the "View" with the controller view?
4.Finally, i can switch from "iphone" Simulator to "ipad" simulator, but i always get the ipad simulator each time i build the projet, is there a way to always let the "iphone" simulator to be the simulator by default?
And that's it. :) Thanks for your help
Paul
1 . Delegation Design Pattern
The delegation design pattern is a way
of modifying complex objects without
subclassing them. Instead of
subclassing, you use the complex
object as is and put any custom code
for modifying the behavior of that
object inside a separate object, which
is referred to as the delegate object.
At predefined times, the complex
object then calls the methods of the
delegate object to give it a chance to
run its custom code.
2 . The reason for creating another viewController is for memory management. It can be done in one line but then you will be needlessly adding an object to the autorelease pool.
//Now the autorelease pool has to track this object
self.mainViewController = [[[MainViewController alloc] initWithNibName:#"MainView" bundle:nil] autorelease];
3 . -(void)loadView is inherited from UIViewController so no you can not just change it to loadViewController because that will just create a custom method. That is exactly what (void)loadFlipsideViewController is trying to accomplish and by the name of it it should load a new view controller and display it using a flip animation.
4 . In XCode 4 you need to set the scheme to the correct simulator.
First of all, it's going to me MUCH easier to get answers if you break all these queries up into separate questions. You're going to have a hard time picking an answer that answers them all best.
That said, I'll give #1 a shot.
Many types of objects in Cocoa (and Cocoa Touch) send messages. Some, like NSFetchedResultsController send messages when their contents change. Some, like UITableViewController, send a message when a table cell is touched. These messages have to GO somewhere. They can't be sent just "out there" or nothing will ever hear them. These messages need a destination. In Cocoa, the destination for these messages is called the "delegate." As in, "I designate this object to be my delegate, and receive my messages."
If you are in a viewController that is controlling a UITableView, very often is makes sense to simply specify "self" as the delegate. That is saying, in effect, hey, Mr. UITableView, just send your messages to me, I'll handle them. In turn, your viewController must declare (in the .h) that they conform to the UITableViewDelegate protocol, and then the required methods in that protocol must be implemented in your .m.
This is a VERY common pattern in Cocoa. Don't proceed until your understand it.
For delegate you can check use of Delegate in iphone sdk. I have a long answer there.
#property (nonatomic, retain) MyClass *obj;
MyClass *tmpObj = [[MyClass alloc] init];
self.obj = tmpObj;
[tmpObj release];
Let's see what happens here. [MyClass alloc] allocates an object and you have retain count of 1. In the next line you are calling the setter which also retains. So you are increasing the retain count. Naturally you will release this property later, may be in dealloc. So now you are owner of this object 2 times. To match the first ownership via alloc you release in the 3rd line.
Now see what happens if you do this in one line:
self.obj = [[MyClass alloc] init];
You have gained ownership here two times, one through alloc and one through retain property. So you need to write [obj release] twice. Otherwise you will have a memory leak. But releasing twice is confusing and easier to create bug and you should never do this. Or you need to autorelease this in the same line which is also confusing.
So the summary is if you have retain property, then write three lines of code to handle with double ownership.
Sorry, can't help with other parts.

NSobject's release query?

hi i am a newbie developer, building my first app, i have a impportant question -
lets say we are using TableviewController and have used few NSMutableArray objects and have a ManagedObjectContext object to fetch the data to display. now if i move to another view and release all the object i have instantiated using [[nsObject alloc] init] in the present view, it all works fine in we are in the next view but as soon as we click back button we dont have the NSObjects thatwe used to create the previous view so the app Crashes. what i did was left the objects without releasing. is it good or bad?
You usually shouldn't be releasing just for pushing another view controller on the stack. You should release when you don't need the objects anymore. In this case, you need the objects still because you are coming back to it. I would release your objects in your dealloc method, called whenever this view controller is done with them and is getting released itself.
If you are determined to release them as you push the app, you will need to re-fetch them when you come back before trying to do anything, this is much more complicated when compared to just retaining them.
Another Idea is to save the data in pList but it depends what you are saving. when you change the view, save it and when you come back again to the same view, retrive it from the plist

objective-c how to synchronize two objects between rootViewController and modalViewController

I'm new to OOP and I'm confused about this following line on chapter 6 of head first iphone development:
addDrinkVC.drinkArray = self.drinks
the purpose is to assign the self.drinks NSMutableArray to another NSMutableArray in modal viewController addDrinkVC.
But why when you added an object into drinkArray in modal view and returned to the rootView and reload the tableView, self.drinks also gets changed? Is it related to the concept of pointer?
Thanks!
Unless drinkArray is declared with #property (copy), the contents of the array are not copied. This does indeed have to do with pointers. Since the array is mutable, and since you are not copying it – only adding a new reference to it – any changes made to either reference will be visible on the other. In other words, there is only one actual array in use.

How to properly pass NSArray / NSMutableArray from one UIViewController to another

An iphone app I'm working on is terminating periodically ... and I have a feeling it is because of how I'm accessing a shared NSArray amongst several view controllers. So ...
What is the best way to pass NSArray/NSMutableArray amongst several ViewControllers ... all of which can modify and/or set it to nil or whatever?
Thanks
There are two approaches, generally speaking.
In the first approach, when you instantiate your next view controller, you could set an array property to "inherit" from the current (soon-to-be previous or parent) view controller:
MyNextViewController *_myNextViewController = [[MyNextViewController alloc] initWithNibName:#"MyNextViewController" bundle:nil];
_myNextViewController.myViewControllerArray = self.myViewControllerArray;
...
In the second approach, you could create a myAppDelegateArray property in your application delegate, instantiating the array when the application initializes (or instantiated somewhere else, on demand).
You can then call the getter for this property from any class — including view controllers.
For example, within an instance of MyNextViewController, you might have a property called myViewControllerArray and you would set it as follows:
self.myViewControllerArray = [UIAppDelegate myAppDelegateArray];
You would add a #define statement somewhere in your application constants file, e.g.:
#define UIAppDelegate ((MyAppDelegate *)[UIApplication sharedApplication].delegate)
or use the full [UIApplication sharedApplication].delegate call, if you prefer.
As a general approach, people seem to prefer the app delegate approach, as it decentralizes access to the desired property.
With this approach, if you rearrange your view controllers or insert new view controllers into your VC hierarchy, you wouldn't need to debug child view controller properties inherited from parent view controllers, because a reference is always available from the app delegate.
you are probably not retaining it, it gets deallocated and you are trying to access it again. try to send a [myArray retain] where you are using it (in each of the controllers), and [myArray release] when you are done with it