iOS: Pointer get lost when poping back to parentView - pointers

I code for iOS 6.1 with ARC and have a problem that my objects in the nsmutablearray get "lost".
I will explain it in more detail:
There is a parent view which has a NSMutableArray which should hold some objects(addresses)
Everytime I hit the button the data of the Array will be displayed with NSLog and then the navigation controller pushes to the ChildView
The childview generates a new address object
If I do this and then press the back button in the view and wants to try the same case (again pressing the button) the data in the array is lost and I get a EXC_BAD_ACCESS
My assumption: When I go back to parentView ARC deallocates the second view and everything in it. But my Address object will be referenced from the array so that the ARC counter for this object should not be 0.
Can anyone help me?
Here is the concrete code
ParentViews Controller h:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (nonatomic, strong) NSMutableArray *adresses;
#property int count;
-(void)goFurther;
#end
ParentViews Controller m:
#import "ViewController.h"
#import "SecondViewController.h"
#import "Address.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
self.title=#"First View";
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithTitle:#"Add address" style:UIBarButtonItemStylePlain
target:self action:#selector(goFurther)];
[self.navigationItem setLeftBarButtonItem:addButton];
self.adresses=[[NSMutableArray alloc] init];
self.count=0;
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void) goFurther{
for (Address *a in self.adresses) {
NSLog(#"Adresse:");
NSLog(a.street);
NSLog(a.door);
}
self.count++;
SecondViewController *second=[[SecondViewController alloc]initWithView:self];
[self.navigationController pushViewController:second animated:true];
}
#end
ChildViews Controller h:
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface SecondViewController : UIViewController
#property ViewController * viewCon;
-(id) initWithView: (ViewController*) view;
#end
ChildViews Controller m:
#import "SecondViewController.h"
#import "Address.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
-(id) initWithView: (ViewController*) view{
self = [super init];
self.viewCon=view;
Address *a=[Address alloc];
a.street=[NSString stringWithFormat:#"Street %d", self.viewCon.count];
a.door=#"Door";
[self.viewCon.adresses addObject: a];
return self;
}
- (void)viewDidLoad
{
self.title=#"Second View";
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end

You have to send your data back to the parent view before dismissing the child view.
Declare a #protocol (say, called ChildControllerDelegate) in your child controller's .h file with a method didDismissWithData: with some data type that is suitable for you (maybe string or dictionary). Have the parent view controller conform to the protocol. Create a #property of the child called delegate of type id<ChildControllerDelegate>
Then before dismissing the child, call
[self.delegate didDismissWithData:newData];
In the parent controller, handle this message and save your new address.

Related

NSPopUpButtonCell error when embedded in an NSTableColumn that is bound

When binding cells in my NSTableView of type NSPopUpButtonCell I got an error
[<NSTableColumn > valueForUndefinedKey:]: this class is not key value coding-compliant for the key value.
The reality is that I am simply after the contents of the NSPopUpButtonCell as a string
But i changed
NSString *name;
to
NSObject *name;
Which made my application LOAD but crash when trying to display the contents to a NSTableView that displays the NSPopUpButtonCell column
ERROR: unrecognized selector sent to instance
When I have an UNBOUND cell, i am not getting an error, further if the cell is type NSTextFieldCell i do not have a problem and can use the NSString class instead.
I am guessing that this is about connecting the right bits to everything, from what I can see on the error, So, how do i have the popup cell to display the popup button but save the value of the selected sell in the actual array?
Thanks
//------------------------------------------------
//my.h
//------------------------------------------------
#interface theItemsInArrayC : NSObject {
#private
NSString *name;
int age;
}
#property int age;
#property (copy) NSString *name;
#end
#interface mybigList : NSObject {
#private
NSMutableArray *theItems;
}
#property (copy) NSMutableArray *theItems;
#end
//------------------------------------------------
AND
//------------------------------------------------
//my.m
//------------------------------------------------
#implementation theItemsInArrayC
#synthesize name;
#synthesize age;
- (id)init
{
self = [super init];
if (self) {
age = 19;
name = #"Another Name";
}
return self;
}
#end
#implementation mybigList
#synthesize theItems;
- (id)init
{
self = [super init];
if (self) {
theItems = [[NSMutableArray alloc] init];
}
return self;
}
#end
//------------------------------------------------
I found the sample code for what i wanted to do at https://github.com/johnjohndoe/NSPopUpButtonCell
i hope this helps the next person!
and also a big thank you to that person on github toooooooo

Passing data back from detailViewController to UITableView

I am currently at the issue where I have a UITableviewCell that needs to be updated.
When the user presses on the uitableviewcell - THERES ONLY 1!!, the user is pushed to a UITABLEVIEWCONTROLLER where the user is allowed to select 1 of multiple cells with their own titles.
I need to get the clicked tableviewcells title and pass the value back to the parentviewcontroller and update the 1 tableviewcell's name to the one the user clicked in the pushed uitableivewcontroller.
Here is a picture of the parent viewcontroller...
And heres the picture of the pushed viewcontroller....
I was told earlier yesterday that delegation would be needed but I am unsure what to do at this point :/.
Heres some code I use in the parent viewcontroller...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
ProblemTypes *view = [[ProblemTypes alloc] init];
[self.navigationController pushViewController:view animated:YES];
}
I am also NOT USING storyboards, just a few xibs.
Also heres the code for the pushedviewcontroller to pop to the parent viewcontroller when a cell is selected...
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSLog(#"Cell's text: %#",cell.textLabel.text);
[self.navigationController popViewControllerAnimated:YES];
}
Thank you guys!
Found it out.... Do delegation was the solution... Just hope it's the MOST EFFICIENT!!! Here's the code for delegation.
First, implement the delegate of the parentViewcontroller and it's methods, also make sure to add delegation to the parentviewcontroller...
#protocol SendFeedBackDelegate
- (void) didReceiveType:(NSString *) message;
#end
#interface SendFeedBackViewController : UIViewController <SKPSMTPMessageDelegate, UITableViewDataSource,UITableViewDelegate, SendFeedBackDelegate>
{
NSString *subject;
}
Next, implement the method : - (void) didReceiveType:(NSString *) message; under
#implementation SendFeedBackViewController
- (void) didReceiveType:(NSString *) message
{
subject = message;
[feedbackTableView reloadData];
// I reload the data because it is needed when this function is going to be called
// in the child viewcontroller.... just keep reading :)
}
Now go to - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath for the use of this example and my project :)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [feedbackTableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// THIS IS THE IMPORTANT PIECE OF CODE YOU NEED TO NOTICE.....
// it allows for the first thing the tableview cell to be is a static string until subject
// it is changed and the user chooses a subject in the childviewcontroller
if (subject == nil) {
cell.textLabel.text = #"Select a Product";
} else {
cell.textLabel.text = subject;
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
Now, add a protocol to the childviewcontroller to allow the childviewcontroller to conform to the parentviewcontroller
In childviewcontroller.h: add these lines of code,
#import "ParentViewController.h"
#protocol SendFeedBackDelegate;
#interface FeedbackTypes : UITableViewController
{
id<SendFeedBackDelegate> delegate;
}
#property (nonatomic, assign) id<SendFeedBackDelegate> delegate;
Now you have set the delegate in the parent viewcontroller.... Next head over the same files implementation file (.m) and add these:
//Add synthesize just under #implementation "ClassName"
#synthesize delegate;
// I used a uitableviewcontroller for this example so refer to the problem I have above
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
//NSLog(#"Cell's text: %#",cell.textLabel.text);
[delegate didReceiveType:cell.textLabel.text];
[self.navigationController popViewControllerAnimated:YES];
}
And THATS IT!!!!..... :), Hope this was a simple and basic tutorial and here's a snapshot.

Cannot make UIPopover appear programmatically

I want the pop-over to appear when the app is first launched in portrait mode instead of it being hidden and requiring the user to hit the button before the popover appears. I've tried to find solutions through the likes of Google and other StackOverflow threads, but I have not been able to figure it out. So in the event the standard SplitView sample that is created by XCode is different I'll put the code below. If I can make it work on this app I'm hoping that I can understand it and be able to apply it elsewhere.
I thought about trying to just call what is called when the button is pushed... but I can't figure out what is called and where it is declared... I feel like I'm overlooking something basic and it's driving me bananas!
The DetailView Controller
DetailViewController.h
#import <UIKit/UIKit.h>
#interface DetailViewController : UIViewController <UIPopoverControllerDelegate, UISplitViewControllerDelegate> {
UIPopoverController *popoverController;
UIToolbar *toolbar;
id detailItem;
UILabel *detailDescriptionLabel;
}
#property (nonatomic, retain) IBOutlet UIToolbar *toolbar;
#property (nonatomic, retain) id detailItem;
#property (nonatomic, retain) IBOutlet UILabel *detailDescriptionLabel;
#end
DetailViewController.m
#import "DetailViewController.h"
#import "RootViewController.h"
#interface DetailViewController ()
#property (nonatomic, retain) UIPopoverController *popoverController;
- (void)configureView;
#end
#implementation DetailViewController
#synthesize toolbar, popoverController, detailItem, detailDescriptionLabel;
#pragma mark -
#pragma mark Managing the detail item
/*
When setting the detail item, update the view and dismiss the popover controller if it's showing.
*/
- (void)setDetailItem:(id)newDetailItem {
if (detailItem != newDetailItem) {
[detailItem release];
detailItem = [newDetailItem retain];
// Update the view.
[self configureView];
}
if (self.popoverController != nil) {
[self.popoverController dismissPopoverAnimated:YES];
}
}
- (void)configureView {
// Update the user interface for the detail item.
detailDescriptionLabel.text = [detailItem description];
}
#pragma mark -
#pragma mark Split view support
- (void)splitViewController: (UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController: (UIPopoverController*)pc {
barButtonItem.title = #"Root List";
NSMutableArray *items = [[toolbar items] mutableCopy];
[items insertObject:barButtonItem atIndex:0];
[toolbar setItems:items animated:YES];
[items release];
self.popoverController = pc;
}
// Called when the view is shown again in the split view, invalidating the button and popover controller.
- (void)splitViewController: (UISplitViewController*)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem {
NSMutableArray *items = [[toolbar items] mutableCopy];
[items removeObjectAtIndex:0];
[toolbar setItems:items animated:YES];
[items release];
self.popoverController = nil;
}
#pragma mark -
#pragma mark Rotation support
// Ensure that the view controller supports rotation and that the split view can therefore show in both portrait and landscape.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
#pragma mark -
#pragma mark View lifecycle
/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
}
*/
/*
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
*/
/*
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
}
*/
/*
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
}
*/
/*
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
}
*/
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.popoverController = nil;
}
#pragma mark -
#pragma mark Memory management
/*
- (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)dealloc {
[popoverController release];
[toolbar release];
[detailItem release];
[detailDescriptionLabel release];
[super dealloc];
}
#end
The rootview is a typical UITableViewController and is nothing special, but if for some reason you need that or the delegate (which is pretty boring minus loading the views) to help me figure out this problem I have no problems posting those also. Again this is straight up what XCode generates when I tell it I want to create a split view for the iPad and I have not modified it.
Hopefully there is something very minor I'm overlooking and it will make me smack my head and say "I can't believe I missed that!" Thanks for your help.
Figured it out!
I put
[self.popoverController presentPopoverFromBarButtonItem:[[toolbar items] objectAtIndex:0] permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
in the ViewDidLoad method. I knew it was something pretty simple! It seems to work without any problems!

When assigning a readonly NSString property of an object, do you still need to [copy]?

I have MyClass setup as below. If the NSString property is readonly it should already be set to copy and autorelease. Do I still need to copy it like below?
MyClass *myClass = [[MyClass alloc] init];
NSString *assignStr = [myClass.returnStr copy];
...
[myClass release];
[assignStr release];
or
MyClass *myClass = [[MyClass alloc] init];
NSString *assignStr = myClass.returnStr;
...
[myClass release];
MyClass.h
#interface MyClass : NSObject {
#private
NSString *returnStr;
}
#property (nonatomic, readonly) NSString *returnStr;
#end
MyClass.m
#implementation MyClass
#synthesize returnStr;
#end
Using the code you provided
#interface MyClass : NSObject {
#private
NSString *returnStr;
}
#property (nonatomic, readonly) NSString *returnStr;
#end
Your property setter is defined with simple assignment
So you can use both code snippet to adjust the assignStr value, it would be correct in term of memory management ; the logical one should be to use the classical assign pattern.
But in fact it is more about, how you are handling the master value (the value you are returning as read-only) and what you want to achieve with it (sorry this is not that clear to me in the provided sample, which does not seems to match 100% your thread title)

UILabel to NSString to load webview

So I have this code, where I am sending a variable storyLink to a label and display it in the specified nib. So far the label displays the text which is what I want. But I want to use that text as an url for a webview. urlString = nothing as of right now because I can't figure out how to use/convert an UILabel to a String suitable for a webview url. So if that was confusing basically I want to take the text stored in my label and use it for the url in my webview. Can someone help?
TestView.h
#interface TestView : UIViewController {
IBOutlet UILabel *label;
IBOutlet UIWebView *webView;
NSString *urlString;
}
#property(nonatomic, retain)IBOutlet UILabel *label;
#property(nonatomic, retain)IBOutlet UIWebView *webView;
#property(nonatomic, retain)NSString *urlString;
#end
TestView.m
- (void)viewDidLoad {
[super viewDidLoad];
label.text=nil;
urlString=something;
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]]];
}
sending code
TestView *objFirstController=[[[TestView alloc] initWithNibName:#"TestView" bundle:nil] autorelease];
[self.navigationController pushViewController:objFirstController animated:YES];
objFirstController.label.text=storyLink;
When setting properties that are accessed during 'viewDidLoad', make sure to put them before you use pushViewController.
TestView.m
- (void)viewDidLoad
{
[super viewDidLoad];
label.text=urlString;
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]]];
}
sending code
TestView *objFirstController = [[[TestView alloc] initWithNibName:#"TestView" bundle:nil] autorelease];
objFirstController.urlString = storyLink;
[self.navigationController pushViewController:objFirstController animated:YES];

Resources