Adding additional text to UITextView

Discussion in 'iOS Programming' started by l0uismustdie, Sep 18, 2010.

  1. l0uismustdie macrumors regular

    l0uismustdie

    Joined:
    Nov 30, 2009
    Location:
    Edinburgh, UK
    #1
    Hello. I have a UITextView setup and I am trying to add additional text and my program runs through the appDelegate. Initially the appDelegate does the following:
    Code:
    //initialize variable and allocate memory
    ResultController	*resultsController = [[ResultController alloc] init];
    NSDateFormatter		*timeFormatter=[[NSDateFormatter alloc]init];
    NSDate				*date=[NSDate date];
    NSString			*timeString;
    	
    //set up timestamp and view
    [timeFormatter setDateFormat:@"dd-MM HH:mm:ss:SS"];
    timeString=[timeFormatter stringFromDate:date];
    results=timeString;
    results=[[results stringByAppendingString:@" Connecting to server...\n"]retain];
    [viewController presentModalViewController:resultsController animated:YES];
    [resultsController setuptextView:results];
    	
    //release memory
    [resultsController release];
    [timeFormatter release];
    	
    //connect to server
    URLRequest *rq = [[[URLRequest alloc]init]autorelease];
    [rq data:self requestSelector:@selector(serverRequest:) withURL:URL andMethod:@"initRequest"];
    
    And the result is successfully displayed in a new view. The setuptextView method is as follows:
    Code:
    -(void)setuptextView:(NSString*)str
    {
    	self.textView = [[[UITextView alloc] initWithFrame:self.view.frame] autorelease];
    	self.textView.textColor = [UIColor blackColor];
    	self.textView.font = [UIFont fontWithName:@"Courier" size:12];
    	self.textView.delegate = self;
    	self.textView.backgroundColor = [UIColor whiteColor];
    	self.textView.text =str;
    	self.textView.returnKeyType = UIReturnKeyDefault;
    	self.textView.keyboardType = UIKeyboardTypeDefault;
    	self.textView.scrollEnabled = YES;
    	
    	
    	self.textView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
    	[self.view addSubview: self.textView];  
    }
    
    So I am putting the timestamp on the beginning of a string and sending it to the setup which works the first time. Then when appDelegate moves into its next function I repeat the same steps:
    Code:
    //initialize variable and allocate memory
    ResultController	*resultsController = [[ResultController alloc] init];
    NSDateFormatter		*timeFormatter=[[NSDateFormatter alloc]init];
    NSDate				*date=[NSDate date];
    NSString			*timeString;
    //set up timestamp and view
    [timeFormatter setDateFormat:@"dd-MM HH:mm:ss:SS"];
    timeString=[timeFormatter stringFromDate:date];
    results=[results stringByAppendingString:timeString];
    results=[results stringByAppendingString:@" Getting data file...\n"];
    [viewController presentModalViewController:resultsController animated:YES];
    NSLog(@"results: %@",results);
    [resultsController setuptextView:results];
    
    //release memory
    [resultsController release];
    [timeFormatter release];
    
    
    Inside of setuptextView I have been printing the variable str to see what is coming in and what should be getting set to self.textView.text and it is the string that I want. However, nothing on the view is changed. Anyone out there see something I am doing wrong???

    Thanks in advance.
     
  2. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #2
    Are you sure you want to even be presenting two modal views? Perhaps you should consider a single modal view presentation of ResultController and then just updating the text, when desired, from within it.
     
  3. Sykte macrumors regular

    Joined:
    Aug 26, 2010
    #3
    I'm confused why you would be doing this out of your appDelegate. Most network operations are asynchronous why not load a view controller and let it handle all of this for you.

    There really isn't a need for you to pass a uitextview from your appDelegate, when your root view could create it.

    I think you're missing a few design patterns that would really help.
     
  4. l0uismustdie thread starter macrumors regular

    l0uismustdie

    Joined:
    Nov 30, 2009
    Location:
    Edinburgh, UK
    #4
    That sounds like a much better idea! However, I'm not really sure how to accomplish something like that. I can't just set the text in the modalview...I tried that
    Code:
    resultsController.textView.text=results;
    [resultsController.view addSubview:resultsController.textView];
    
    I guess I am not really sure how to manipulate the modalviewcontroller.
     
  5. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
  6. l0uismustdie thread starter macrumors regular

    l0uismustdie

    Joined:
    Nov 30, 2009
    Location:
    Edinburgh, UK
    #6
    I took a look at the suggested site and what I came up with for the best strategy is: 1. change the view 2. set the view to "dirty" and let the system redraw it. Upon further reading I read that this is only implemented with the view's drawRect: method, of which I have none. I'm wondering if this is the ideal approach? I attempted to implement this strategy with no success using the following code(probably because I have no drawRect: ):
    Code:
    [resultsController setuptextView:results];
    [viewController.view setNeedsDisplay];
    
    And though this is clearly a poor idea I attempted to dismiss the view and just create a new one that displayed the previous text plus this additional text with the following code:
    Code:
    [resultsController dismissModalViewControllerAnimated:NO];
    [viewController presentModalViewController:resultsController animated:NO];
    
    The interesting thing about this second code is that it worked the first time I ran my application but hasn't worked since...

    I essentially just want to redraw the view periodically...
     
  7. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #7
    What about using something like?:
    Code:
    -(void)updateTextView:(NSString*)str
    {
    	self.textView.text =str;
    }
    This would be a method within your ResultsController.
     
  8. l0uismustdie thread starter macrumors regular

    l0uismustdie

    Joined:
    Nov 30, 2009
    Location:
    Edinburgh, UK
    #8
    Yeah that is part of the method that is already there:
    Code:
    -(void)setuptextView:(NSString*)str
    {
    	self.textView = [[[UITextView alloc] initWithFrame:self.view.frame] autorelease];
    	self.textView.textColor = [UIColor blackColor];
    	self.textView.font = [UIFont fontWithName:@"Courier" size:12];
    	self.textView.delegate = self;
    	self.textView.backgroundColor = [UIColor whiteColor];
    	self.textView.text =str;
    	self.textView.returnKeyType = UIReturnKeyDefault;
    	self.textView.keyboardType = UIKeyboardTypeDefault;
    	self.textView.scrollEnabled = YES;
    	
    	
    	self.textView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
    	[self.view addSubview: self.textView];  
    }
    
    Is there a step that needs to happen once the view is updating that I am missing?
    Code:
    //initialize variable and allocate memory
    ResultController	*resultsController = [[ResultController alloc] init];
    NSDateFormatter		*timeFormatter=[[NSDateFormatter alloc]init];
    NSDate				*date=[NSDate date];
    NSString			*timeString;
    
    //set up timestamp and view
    [timeFormatter setDateFormat:@"dd-MM HH:mm:ss:SS"];
    timeString=[timeFormatter stringFromDate:date];
    results=[results stringByAppendingString:timeString];
    [results=[results stringByAppendingString:@" Getting data file...\n"]retain];
    [resultsController updateTextView:results];
    
    //release memory
    [resultsController release];
    [timeFormatter release];
    
    Something that tells the view it has been updated and need to redraw itself?
     
  9. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #9
    Your design is way off base here. You don't understand the view controller life-cycle, as explained in the view controller programming guide. Here's how this is usually done:

    Build the view hierarchy in a nib, or in loadView, or in viewDidLoad. That's where the views come from. If you need to manipulate the view controller's data from outside the view controller you provide the info to the view controller either in its init method or in a property.

    So you create the view controller, set the data, load the data into the view controller's views in its viewDidLoad method.

    Doing it the way you're doing it won't work correctly in the case of a memory warning and it violates the uiviewcontroller design.
     
  10. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #10
    Did you notice that my method doesn't create a new textView though, but just updates the current one?
     
  11. l0uismustdie thread starter macrumors regular

    l0uismustdie

    Joined:
    Nov 30, 2009
    Location:
    Edinburgh, UK
    #11
    Yeah, dejo I have your update method running and I am still not getting any result from calling it.
    Code:
    results=[results stringByAppendingString:timeString];
    [results=[results stringByAppendingString:@" Getting data file...\n"]retain];
    [resultsController updateTextView:results];
    
    Phoney...I am sort of doing that. textView is my property that I am trying to manipulate from outside the viewController. Is there some other property that I should have?
     
  12. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #12
    Remember that the viewcontroller's view doesn't exist until viewDidLoad has been called.

    Manipulating views from outside the view controller is usually a bad idea. Manipulate the data instead, and let the view controller manipulate it's views.

    In this case the data is a string. Have a property for that string. Set the text property of the textview to that string in viewDidLoad.
     
  13. l0uismustdie thread starter macrumors regular

    l0uismustdie

    Joined:
    Nov 30, 2009
    Location:
    Edinburgh, UK
    #13
    I think I am picking up what you're putting down. So my plan is this: set up a property for the viewController containing the display string. When the view gets loaded set this string to the current text on the screen. Here is my implementation:
    Code:
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    	self.textView.text=displayText;
    	NSLog(@"display:%@",displayText);
    }
    
    Then to add some text to the view I do the following:
    Code:
    results=[[results stringByAppendingString:@" Connecting to server...\n"]retain];
    resultsController.displayText=results;
    [viewController presentModalViewController:resultsController animated:NO];
    
    This isn't producing any results but I feel that there is a detail I am neglecting
     
  14. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #14
    OK, that code looks much better and should work. What is the value of self.textView in viewDidLoad?
     
  15. l0uismustdie thread starter macrumors regular

    l0uismustdie

    Joined:
    Nov 30, 2009
    Location:
    Edinburgh, UK
    #15
    Running the following code:
    Code:
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    	self.textView.text=displayText;
    	NSLog(@"display:%@",self.textView);
    }
    
    Produces this results:
    Code:
    2010-09-20 14:52:24.953 vm[69122:207] display:(null)
    
    Code:
    Code:
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    	self.textView.text=displayText;
    	NSLog(@"display:%@",displayText);
    }
    
    Result:
    Code:
    2010-09-20 14:53:55.668 vm[69170:207] display:20-09 14:53:55:67 Connecting to server...
    
    Additionally this is how I am setting up the view:
    Code:
    //initialize variable and allocate memory
    ResultController	*resultsController = [[ResultController alloc] init];
    NSDateFormatter		*timeFormatter=[[NSDateFormatter alloc]init];
    NSDate				*date=[NSDate date];
    NSString			*timeString;
    //set up timestamp and view
    [timeFormatter setDateFormat:@"dd-MM HH:mm:ss:SS"];
    timeString=[timeFormatter stringFromDate:date];
    results=timeString;
    results=[[results stringByAppendingString:@" Connecting to server...\n"]retain];
    resultsController.displayText=results;
    [viewController presentModalViewController:resultsController animated:YES];
    
    I have also tried running setuptextView: before and after I set resultsController.displayText
     
  16. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #16
    Well, it's not working because self.textView is nil. You should create the textView in loadView or viewDidLoad or in a nib and when you do you should set the property. Then it will work.
     
  17. l0uismustdie thread starter macrumors regular

    l0uismustdie

    Joined:
    Nov 30, 2009
    Location:
    Edinburgh, UK
    #17
    Yeah...I thought I was doing that in the setuptextView: function but I think the view was being released before I used it.
    I've since added the following to my viewDidLoad: method
    Code:
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    	self.textView = [[[UITextView alloc] initWithFrame:self.view.frame] autorelease];
    	self.textView.text=displayText;
    	[self.view addSubview:self.textView];
    	NSLog(@"textView:%@",self.textView);
    	NSLog(@"test:%@",displayText);
    }
    
    Then in an attempt to load the views I am doing the following
    Code:
    [timeFormatter setDateFormat:@"dd-MM HH:mm:ss:SS"];
    timeString=[timeFormatter stringFromDate:date];
    results=timeString;
    results=[[results stringByAppendingString:@" Connecting to server...\n"]retain];
    resultsController.displayText=results;
    [viewController presentModalViewController:resultsController animated:NO];
    
    Then when I want to update the view I do the following
    Code:
    [timeFormatter setDateFormat:@"dd-MM HH:mm:ss:SS"];
    timeString=[timeFormatter stringFromDate:date];
    results=[results stringByAppendingString:timeString];
    results=[[results stringByAppendingString:@" Getting data file...\n"]retain];
    resultsController.displayText=results;
    [resultsController presentModalViewController:resultsController animated:NO];
    
    The only thing that is being displayed is the timestamp and "Connecting to server..."

    Here is my output:
    Code:
    010-09-20 21:56:23.845 vm[74084:207] textView:<UITextView: 0x5d38a00; frame = (0 0; 320 460); text = '20-09 21:56:23:83 Connect...'; clipsToBounds = YES; layer = <CALayer: 0x5d38be0>; contentOffset: {0, 0}>
    2010-09-20 21:56:23.846 vm[74084:207] test:20-09 21:56:23:83 Connecting to server...
    2010-09-20 21:56:23.852 vm[74084:207] textView:<UITextView: 0x5d3e970; frame = (0 0; 320 460); text = '20-09 21:56:23:83 Connect...'; clipsToBounds = YES; layer = <CALayer: 0x5d364c0>; contentOffset: {0, 0}>
    2010-09-20 21:56:23.853 vm[74084:207] test:20-09 21:56:23:83 Connecting to server...
    20-09 21:56:23:85 Getting data file...
    
     
  18. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #18
    What do you mean by "update the view?" It looks like you are presenting a new view controller with a new textview. Is that your intention? The log output shows that there are two different textview objects. Is that what you want?

    If not then you need to message the first view controller and have the method save the new text string into the displayText property and update the textview with this new string.
     
  19. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #19
    You will probably end up not wanting to present two modal views consecutively, but a word of warning if you ever do: if you don't present the second modal view from within the viewController for the first modal view, it won't be seen! I'm sure this is the cause of some of your issues. But, I wouldn't try to fix it; change direction and use one modal view with dynamic content.
     

Share This Page