How to remove a childviewcontroller using objectAtIndex - iphone

I got a ViewController where I add many childs on like this:
[self addChildViewController:myViewController];
After this I want to remove some of the childs dependent on where I am in my program to free up memory. So I was thinking of something like this:
[self.childViewControllers objectAtIndex:1]
and then use removeFromParentViewController. But how can I provide this code on objectAtIndex?
I also tried: [self.childViewControllers objectAtIndex:1] = nil;
But this doesn't work, I get the error that the expression is not assignable.

You can get an array of view controllers by doing "[self.navigationController viewControllers]".
Then you can get any one of them via "objectAtIndex:" on that array.
When you get any one of them, you can call removeFromParentViewController" on that view controller.
However, I wouldn't do what you're trying to do. This is going to likely to confuse the heck out of your users, who were navigating through your app thinking they came from one specific view controller, only now when they back up they're going back to somewhere unexpected.

Related

Releasing after pushing in iOS

So I have the following code where I am releasing an object after pushing it to another view. When I analyse it I get the error - Incorrect decrement of the reference count of an object that is not owned at this point by the caller. Would anyone know how to fix this? I've tried so many options each time getting a different memory leak
- (void)showCurrentArticle:(id)sender {
if(animating)
return; //it is already there
animating = YES;
JsonViewController *newsController = [(JsonViewController *)[self.newsNavController.viewControllers objectAtIndex:0]retain];
newsNavController.title = #"Parliament";
Item *currentItem = (Item *)[self.fetchedObjectsArray objectAtIndex:currentItemIndex];
NSString * urlString = [CONST_FEED_DISCRIPTION_URL stringByAppendingString:currentItem.guid];
[newsController initWithURLString:urlString date:currentItem.date];
[self.navigationController pushViewController:newsController animated:YES];
[newsController release];
}
This code takes a view controller that's already present in the navigation stack, reinitialises it, then pushes it onto the stack again. This doesn't seem right at all. You probably should be creating a new view controller. What's the background on this? What are you trying to achieve?
You are popping, change a title, than you are doing an initialization...
Decide if you will do deep clone of JsonViewController (alloc, init, copy field values) or just reference copy (retain). It will be mess later if you try to mix.
Your retain and release of the newsController object are unnecessary. That is why you are getting the warning. It looks like newsController is owned by the newsNavController object, which will retain it. The only reason you would need to retain newsController in this code is if you needed to use it outside the scope of this method. Since you don't need to retain it, you don't need to release it, hence the error. You may be assuming that the -initWithURLString:date: method is incrementing the retain count, but it is only new, alloc, and retain that do this. You should probably rename that method to not use the term init to avoid confusion.
What are you doing with -initWithURLString:date:??? Are you just adding a url? Then you should call it addURL...... If you really initialize it again, you set the pointer of the newsController variable to a new object. The first object it pointed to gets lost -> leak.
I assume you named the init method wrong and just add a url to a controller, which is already in the stack and add it again with a higher retain count, but still the very same object.
Don't do this. Copy the object or better - create a new instance of the viewController!!!

pass int variable to UITableView Through UINavigationController

I'm trying to pass int variable to UITableView through UINavigationController (I'm using xcode 4.3) So I created 2 classes (PartsTableViewController that is "UITableViewController" and PartsNavController that is "UINavigationController"), I want to pass the variable from my current class to PartsTableViewController and then open that table with its Navigation controller that contains the title bar , so I wrote in my current class the following code:
PartsNavController *partsNav = [self.storyboard instantiateViewControllerWithIdentifier:#"partsNav"];
partsNav.groupId = myGroupp.bg_id;
[self presentModalViewController:partsNav animated:YES];
and in the PartsNavController class I wrote in viewDidLoad:
PartsTableViewController *parts = [self.storyboard instantiateViewControllerWithIdentifier:#"Parts"];
parts.groupId = groupId;
[parts.tableView reloadData];
and in PartsTableViewController I wrote in viewDidLoad:
NSLog(#"This is group: %d", groupId);
but when run, it generates the output 2 times,
This is group:1
This is group:0
first time is the value that I sent and the second time it outs 0 , I just want the value that I sent, not 0
how can I prevent this and get just the value that I sent ????
I want to pass from (MaktabatyTableViewController) to (PartsTableViewController) without using segue
The better way to do what you want is to push second TableViewController in existing UINavigationController. The easiest way to do that is to create that NavContr in StoryBoard and than to TableViews and connect it's cell with leading view controller with segue. And than use method below:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
UIViewController *destViewController = segue.destinationViewController;
destViewController.integerValue = value;
}
I want to pass from (MaktabatyTableViewController) to
(PartsTableViewController) without using segue
There are (at least) two strategies you can choose from:
Direct communication: People often ask how to communicate between two objects, and it almost always boils down one of the objects having a reference to the other (and sometimes vice versa). To send a message to an object, you need a pointer to that object; if you've got the pointer, there's no mystery about how to communicate. Thinking about it in those terms helps you think about the issue a little differently: instead of the immediate "how do I send a message to that object?" you can instead focus on the relationship between the two objects. How was each one created? Is one of the objects the parent of the other? Is there some common parent object that can provide a pointer? How should the objects be related, if at all?
Indirect communication: Sometimes instead of having two objects communicate directly, it's more appropriate to route the communication through some intermediate object. For example, your MaktabatyTableViewController might send a message to its delegate, and the delegate could then pass the information on to PartsTableViewController. A much more general solution is to use notifications: MaktabatyTableViewController could post a notification that PartsTableViewController listens for. The intermediate object in this case is the notification center. Either way, the advantage that you get with indirect communication is that neither object has to know about the other. That reduces coupling between the two classes and makes them both more flexible and more reusable.
From what I can see in your question, I'd suggest using notifications.

Tricky memory management in objective-c

After reading:
Memory management of a view controller in Objective-c
and
Does UIView's addSubview really retain the view?
I wrote the following code to toggle a subview:
#synthesize switchableView, viewSelector, currentSubview;
//...
if(switchableView.subviews.count != 0)
[[switchableView.subviews objectAtIndex:0] removeFromSuperview]]
self.currentSubview = (veiwSelector.selectedSegmentIndex == 0) ?
[ViewA new] : [ViewB new];
[switchableView addSubview:currentSubview.view];
//[currentSubview release]; //<---crashes if I uncomment this line
It seems to run fine if I comment out that release line, but I can't wrap my head around why. Here's the way I understand what happens and maybe someone can tell me where I go wrong:
So lets consider currentView:
A gets alloc-ed by the 'new' message--retain count=A:1
A gets retained by the setter--retain count=A:2
A's view gets (supposedly) retained--retain count=A:2.1
next time through...
A's subview gets released count=A:2
B gets alloc-ed by the 'new' message--retain count=B:1, A:2
A gets autoreleased by the setter-- B:1, A:1
B gets retained by the setter--B:1, A:1
nothing ever gets rid of A?
So should I change my code, or am I wrong about the way memory management works in this language...or both?-
Ok, step one, ignore the retainCount. It's one of those things Apple should rename to something like lsdjiofsudfoiwjeriowhfiuwhrteiuhweifhsdjkfhsiurwoieuriosfho so people won't guess it's name, and not list it in the documentation. For your purposes, it's entirely useless, so ignore it.
Now that I've said that, let's consider something: addSubview: DOES retain its argument, and removeFromSuperview releases the receiver.
Finally, it's hard to tell what currentSubview is. It has a view property which would lean towards a VC, however, the way you're using it by itself, would indicate its a normal view. Perhaps you can clarify so I can continue my answer.
Your understanding of retain and release is correct, as is your code. That suggests that the problem lies outside of the code you've posted. For example, you would have this problem if your currentSubView property was defined as assign instead of retain.
You code is not structured well, however. This would be much clearer:
self.currentSubView = [[ViewA new] autorelease];
Furthermore, view controllers are meant to be cached, not created and released each time the user toggles a display. Typically, you create your view controllers beforehand, and access their .view property when necessary to display the view. UIViewController will automatically deallocate non-visible views in low memory conditions, and re-allocate their view when the .view property is accessed.
Change the release line to
self.currentSubview = nil;
and I think you'll be fine. You're releasing, but not setting the property to nil. So, when it gets re-assigned next time through, release will be called again on it. But you already released it so... boom.

Passing a dictionary from view controllers

In one of my Navigation view controllers I build an array of dictionaries to display in a table. Based on which one I select I then remove the dictionary from the array using
NSDictionary *notice = [notices objectAtIndex: roomIndex];
I create the new view controller using
Feed *notice_view = [[Notice alloc] initWithObject: notice];
I push the navigation view controller and I've implemented initWithObject which takes a Dictionary.
I release the notice and notice_view and all this works fine but if I selected go back, select it go back about the third or forth time the whole app crashes. If I dont release both of them it works fine no problems what so ever, except of course the memory leaks.If i only release one of them, either of them, it fails again. What gives? Should I not be using initWithObject or should I be passing it in some other way? I've also tried using autorelease but with the same result.
notice - you should not release, since you don't own the object(you are just using a object which is returned from NSArray) else retain this object when you retrieve the object from NSArray and release it later stage.
notice_view - as per you explanation I don't see any issue with releasing, I am assuming you don't have any reference to this object from other part of the code.
I'm guessing you'll want to get rid of [selectedNotice release], since there doesn't seem to be a corresponding -retain call in there.

Count method of subclass of NSMutableArray crashes app

This seems to be a common problem, but I can't figure out anything from the answers I've seen so far. I have an iPhone app that uses a subclass of NSMutableArray to store objects, plus some additional properties. The subclass is skhCustomArray. The subclass initializes fine, with no objects in the skhCustomArray, and I assign it to the the property of my view controller, which is a pointer to an skhCustomArray.
prescriptionListVC* newPrescList = [[prescriptionListVC alloc] initWithNibName:#"PrescriptionList" bundle:nil];
newPrescList.curPersonPrescriptions = [personDetails objectAtIndex:0];
That works fine. Yet when I push my view managed by my view controller onto the navigation controller stack, the count method in the numberOfRowsInSection method crashes the app, see below.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [curPersonPrescriptions count];
}
What could be causing this? How can a valid custom array, with no objects, not return a valid count? Where am I going wrong? Thanks.
Subclass of NSArray? You're aware that NSArray is a class cluster, and is therefore somewhat difficult to subclass, right? In fact, it's so fraught with danger that the NSArray documentation has a whole section dedicated to what you need to do in order to subclass it.
I'll bet that that's the source of your woes.
You almost certainly don't need to subclass NSMutableArray in this situation. Instead, make a new class which has an array as a property, along with the extra properties you desire.
When you subclass NSMutableArray, you need to implement some mandatory methods like count, addObject:, insertObjectAtIndex etc. This is what we call as class cluster.
If you want to add some more feature/behavior to already implemented object then you can write a "category" instead of "subclassing" it.
If you want to subclass it, then you have to implement all those methods which your are going to use so better write a category of NSMutableArray and extend the feature what you want and use the NSMutableArray object only. This will solve your problem and also this is the easy and almost right way to add new behavior to already existing class.