Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

StarLion

macrumors newbie
Original poster
Jan 3, 2011
12
0
(Yay. More newbishness.)

Okay so, after the headaches of running around trying to stuff square pegs into round holes, i downloaded one of Apple's sample codes (MultipleDetailViews) and started jamming my stuff into their templates instead.

I've run into a slight issue though.

RootViewController is handling the item selection, as it should, and is doing it in this manner:
Code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    
    /*
     Create and configure a new detail view controller appropriate for the selection.
     */
    curfile = [[[indexItems objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] objectForKey:@"filename"];
    UIViewController <SubstitutableDetailViewController> *detailViewController = nil;

    if (curfile != @"Calculator") {
        FirstDetailViewController *newDetailViewController = [[FirstDetailViewController alloc] initWithNibName:@"FirstDetailView" bundle:nil];
        detailViewController = newDetailViewController;
    } else {
        SecondDetailViewController *newDetailViewController = [[SecondDetailViewController alloc] initWithNibName:@"SecondDetailView" bundle:nil];
        detailViewController = newDetailViewController;
    }

    // Update the split view controller's view controllers array.
    NSArray *viewControllers = [[NSArray alloc] initWithObjects:self.navigationController, detailViewController, nil];
    splitViewController.viewControllers = viewControllers;
    [viewControllers release];
    
    // Dismiss the popover if it's present.
    if (popoverController != nil) {
        [popoverController dismissPopoverAnimated:YES];
    }

    // Configure the new view controller's popover button (after the view has been displayed and its toolbar/navigation bar has been created).
    if (rootPopoverButtonItem != nil) {
        [detailViewController showRootPopoverButtonItem:self.rootPopoverButtonItem];
    }

    [detailViewController release];
}
Which works fine.
But; I need to put information into the textarea (UITextView *textarea) of the FirstDetailViewController instance, based on the curfile variable.
I tried detailViewController.textarea.text = @"Some text", but was told that I couldnt do that 'in something not a structure or union'. Whatever that means.

FirstDetailViewController obviously doesnt have access to the curfile variable at runtime, and has no way of knowing which item was selected from the menu.

What am I missing here?
 

StarLion

macrumors newbie
Original poster
Jan 3, 2011
12
0
It did, but eventually it dawned on me that i managed to forget i could call functions with parameters lol.

so RootViewController.m now calls
Code:
        detailViewController = newDetailViewController;
		[detailViewController settext:curfile];

with FirstDetailViewController now containing the function
Code:
- (void)settext:(NSString *)curfile {
   	NSString *quack2=[[NSBundle mainBundle] pathForResource:curfile ofType:@"txt"];
	NSString *quack=[[NSString alloc] initWithContentsOfFile:quack2];
    textarea.text = quack;
}
(Using the quacks for breakpoint checking.)

The function fires.
Quack gets set correctly.
textarea is linked in IB. (and saved)
But the display doesn't show the changed text.
I'm confused.
 

dejo

Moderator emeritus
Sep 2, 2004
15,982
452
The Centennial State
It did, but eventually it dawned on me that i managed to forget i could call functions with parameters lol.
Not sure you needed to abandon troubleshooting that error, but fine...

so RootViewController.m now calls
Code:
        detailViewController = newDetailViewController;
		[detailViewController settext:curfile];

with FirstDetailViewController now containing the function
Code:
- (void)settext:(NSString *)curfile {
   	NSString *quack2=[[NSBundle mainBundle] pathForResource:curfile ofType:@"txt"];
	NSString *quack=[[NSString alloc] initWithContentsOfFile:quack2];
    textarea.text = quack;
}
(Using the quacks for breakpoint checking.)

The function fires.
Quack gets set correctly.
textarea is linked in IB. (and saved)
But the display doesn't show the changed text.
I'm confused.
What are you doing to retain the value assigned to quack? Since textarea is a property, (my apologies if I'm sounding like a broken record on this lately) you should assign it using the synthesized accessors and not reference the ivar that backs it directly.

Here's a tip: if you have property, name the ivar that backs it with a leading underscore, as in the following code:
Code:
@interface SampleAppViewController : UIViewController {
	UITextView *_textarea;
}
@property (nonatomic, retain) IBOutlet UITextView *textarea;

@end

@implementation SampleAppViewController

@synthesize textarea = _textarea;

...
Then when you try to do something like:
Code:
textarea.text = quack;
you will get a compile-time error, since there is no ivar named textarea.
 

StarLion

macrumors newbie
Original poster
Jan 3, 2011
12
0
Well i dont get an error. The program runs, it just doesnt do what i think it's supposed to.

Quack doesnt need to (and shouldnt) be retained - it's not used anywhere else, and is re-assigned every time the script fires, making retaining it rather silly, unless i'm missing something here.
.h
Code:
@interface FirstDetailViewController : UIViewController <SubstitutableDetailViewController> {

    UIToolbar *toolbar;
	UITextView *textarea;
}

@property (nonatomic, retain) IBOutlet UIToolbar *toolbar;
@property (nonatomic, retain) IBOutlet UITextView *textarea;

@end
.m
Code:
@synthesize toolbar,textarea;

Forgive me for being somewhat dense... but why would I -want- to give myself a compile-time error by changing the reference to textarea, when leaving it as is should work?

Why do you say textarea is a property? It's not a reserved word of any class relating to UITextView, and nothing stops this code from working properly when i do this in a regular view app...

Edit: I modified the synthesis line to be @synthesize toolbar,textarea = _textarea; and the appropriate line to _textarea.text = quack; . No change at all in the program.
 
Last edited:

dejo

Moderator emeritus
Sep 2, 2004
15,982
452
The Centennial State
Sorry, I'm confused. Just ignore what I said.

EDIT:

Anyways, seems to me that you should verify that textarea is not nil before you try to assign its text.
 
Last edited:

StarLion

macrumors newbie
Original poster
Jan 3, 2011
12
0
You're correct, it is coming up as 0x0 when i do:
Code:
	UITextView *temp=textarea;
(temp = 0x0)

... but why? it's linked in IB, part of the interface in the header, propertied, synthesized....
 

dejo

Moderator emeritus
Sep 2, 2004
15,982
452
The Centennial State
It has not yet been assigned to the property at the time you are referencing it. View loading fun, I like to call it. Somehow you need to delay the setting of the text, in order to allow textarea to become non-nil.
 

PhoneyDeveloper

macrumors 68040
Sep 2, 2008
3,114
93
In general it's bad to directly access views that belong to one view controller from some other object. The fact that you're forced to make public properties for all your outlets makes you think that it's ok to do this.

As dejo points out the views aren't loaded until the nib is loaded. The correct way to solve this is to add a string property to the view controller, and then use the value of that property in viewDidLoad to set the text of your text view. The case where your views are unloaded due to a memory warning will be solved in that case while setting the text of the view from outside the class will not work correctly.
 

StarLion

macrumors newbie
Original poster
Jan 3, 2011
12
0
Yay for fun.

I did pretty much exactly what Phoney said...

(cfile is a declared/synthesized/retained NSString)
Code:
- (void)settext:(NSString *)curfile {
	cfile = curfile;
}

- (void)viewDidLoad {
	[super viewDidLoad];
    textarea.text = [[NSString alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:cfile ofType:@"txt"]];
}
works as intended now :D Thank you both for your patience!
 

PhoneyDeveloper

macrumors 68040
Sep 2, 2008
3,114
93
Glad it's working. Couple comments:

If cfile is already a property then I don't understand why you need the settext setter.

You're leaking memory on the line where you assign the string to textarea.text.
 

StarLion

macrumors newbie
Original poster
Jan 3, 2011
12
0
Glad it's working. Couple comments:

If cfile is already a property then I don't understand why you need the settext setter.

You're leaking memory on the line where you assign the string to textarea.text.

Okay... the setter is there because viewDidLoad doesnt take parameters? I'm confused here. The function thats being fired is inside RootViewController, which then creates an instance of the FirstDetailViewController. The FirstDetailViewController has a property, cfile, but thats blank at instantiation. I cant use detailViewController.cfile = curfile because that throws the 'not in a union or structure' error. So how would i set a property of an object from another object without that structure?

No idea where i'm leaking memory in assigning the string... so no idea how to fix it.

Additionally: Now i need to do things in reverse. I have a button in the toolbar of one of my views (Which is now called InfoViewController) that needs to go up a level to the RootViewController and fire the view-changing command... is that even possible?
 

dejo

Moderator emeritus
Sep 2, 2004
15,982
452
The Centennial State
Okay... the setter is there because viewDidLoad doesnt take parameters? I'm confused here. The function thats being fired is inside RootViewController, which then creates an instance of the FirstDetailViewController. The FirstDetailViewController has a property, cfile, but thats blank at instantiation. I cant use detailViewController.cfile = curfile because that throws the 'not in a union or structure' error. So how would i set a property of an object from another object without that structure?
What is the class of your detailViewController object when you try to make this assignment? Is it a FirstDetailViewController or a UIViewController?
 

PhoneyDeveloper

macrumors 68040
Sep 2, 2008
3,114
93
There's no reason why you shouldn't be able to set the value of a public property from another class.

Code:
detailViewController.cfile = curfile;

Should work. If you get compiler errors you should show us the header file and the code that creates the object and sets the property.
 

StarLion

macrumors newbie
Original poster
Jan 3, 2011
12
0
Code:
    UIViewController <SubstitutableDetailViewController> *detailViewController = nil;

    if (curfile != @"Calculator") {
        InfoViewController *newDetailViewController = [[InfoViewController alloc] initWithNibName:@"InfoView" bundle:nil];
        detailViewController = newDetailViewController;
		[detailViewController settext:curfile];
so it's a UIViewController pointer that implements the SubstituteableDetailViewController protocol (at least, thats how i read that line. I could be wrong)

SubstitutableDetailViewController is defined in RootViewController.h as:
Code:
@protocol SubstitutableDetailViewController
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem;
- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem;
- (void)settext:(NSString *)curfile;
@end

InfoViewController is defined by InfoViewController.h as
Code:
#import <UIKit/UIKit.h>
#import "RootViewController.h";

@interface InfoViewController : UIViewController <SubstitutableDetailViewController> {

    UIToolbar *toolbar;
	UITextView *textarea;
	NSString *cfile;	
}

@property (nonatomic, retain) IBOutlet UIToolbar *toolbar;
@property (nonatomic, retain) IBOutlet UITextView *textarea;
@property (nonatomic, retain) IBOutlet NSString *cfile;

-(IBAction) loadCalc:(id) sender;
-(void) settext:(NSString *) curfile;

@end
(loadCalc is the function that is tied to the new button that needs to somehow change the view of the RootViewController. Currently not working.)

EDIT: Looking at it, i have no idea why I IBOutlet'd cfile, since... it's not tied to an IB object.
 
Last edited:

StarLion

macrumors newbie
Original poster
Jan 3, 2011
12
0
Well it makes sense that it has no cfile property, so using the setter was appropriate.... so i'm not sure why i was told not to use the setter :p
 
Last edited:

dejo

Moderator emeritus
Sep 2, 2004
15,982
452
The Centennial State
Well it makes sense that it has no cfile property...
And that reason is? Sorry if I'm pushing so hard on this but I'm trying to get you to explain why it makes sense rather than just agreeing. Then, once you do, you might also see that you already have a variable whose class does have a cfile property that you can set through its synthesized accessor.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.