I am using Xcode 4.3 and I have a label in one view controller that I want to update the text in a text field in another view controller. How should I do this?
You should put the text in your model class (assuming that you have one; if you don't, you need to create it). When the end-user edits the text field, your code should change the string in your model; when the label displays, you should read its text from the model. The easiest way of sharing your model among multiple classes is to define a singleton.
Header:
#interface Model : NSObject
#property (NSString*) labelText;
+(Model*)instance;
#end
Implementation:
#implementation Model
#synthesize labelText;
+(Model*)instance{
static Model *inst;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
inst = [[Model alloc] init];
});
return inst;
}
-(id)init {
if (self = [super init]) {
labelText = #"Initial Text";
}
return self;
}
#end
Using the model:
// Setting the field in the model, presumably in textFieldDidEndEditing:
// of your UITextField delegate
[Model instance].labelText = textField.text;
// Getting the field from the model, presumably in viewWillAppear
myLabel.text = [Model instance].labelText;
Related
As the title suggests, I am looking for a way to export a .NET MVC View to a PDF.
My program works like this:
Page 1
Takes in information
Page 2
Takes this information and heavily styles it with CSS etc
So basically I need to save page 2 after it has been processed and used the information from Page 1's model.
Thanks in advance!
To render a non-static page to a pdf, you need to render the page to a string, using a ViewModel, and then convert to a pdf:
Firstly, create a method RenderViewToString in a static class, that can be referenced in a Controller:
public static class StringUtilities
{
public static string RenderViewToString(ControllerContext context, string viewPath, object model = null, bool partial = false)
{
// first find the ViewEngine for this view
ViewEngineResult viewEngineResult = null;
if (partial)
{
viewEngineResult = ViewEngines.Engines.FindPartialView(context, viewPath);
}
else
{
viewEngineResult = ViewEngines.Engines.FindView(context, viewPath, null);
}
if (viewEngineResult == null)
{
throw new FileNotFoundException("View cannot be found.");
}
// get the view and attach the model to view data
var view = viewEngineResult.View;
context.Controller.ViewData.Model = model;
string result = null;
using (var sw = new StringWriter())
{
var ctx = new ViewContext(context, view, context.Controller.ViewData, context.Controller.TempData, sw);
view.Render(ctx, sw);
result = sw.ToString();
}
return result.Trim();
}
}
Then, in your Controller:
var viewModel = new YourViewModelName
{
// Assign ViewModel values
}
// Render the View to a string using the Method defined above
var viewToString = StringUtilities.RenderViewToString(ControllerContext, "~/Views/PathToView/ViewToRender.cshtml", viewModel, true);
You then have the view, generated by a ViewModel, as a string that can be converted to a pdf, using one of the libraries out there.
Hope it helps, or at least sets you on the way.
We are currently trying to create an action that returns a JsonResult and at certain times that action should also return some HTML inside it along with the other data. Is it possible to generate the HTML from another action that returns a PartialViewResult?
I think this is what you want to achieve.
Generate HTML from another action sounds strange.
You may get the same model from your repository and then render the same PartialView. You will need a method like the following.
// in a RenderingHelper class
public static string RenderViewToString(ControllerContext context, string viewName, object model)
{
if (string.IsNullOrEmpty(viewName))
viewName = context.RouteData.GetRequiredString("action");
ViewDataDictionary viewData = new ViewDataDictionary(model);
using (StringWriter sw = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(context, viewName);
ViewContext viewContext = new ViewContext(context, viewResult.View, viewData, new TempDataDictionary(), sw);
viewResult.View.Render(viewContext, sw);
return sw.GetStringBuilder().ToString();
}
}
And then you will render the partial view accordingly:
string renderedHtml = RenderingHelper.RenderViewToString(this.ControllerContext, "~/Views/MyController/MyPartial", viewModel);
Where viewModel is the model used by "other action" too and "~/Views/MyController/MyPartial"is the partial view used by "other action" too.
I know there is very simple question, but few hours I can not do this.
I got 2 classes:
1. LoginViewController : UIViewController
2. WebRequests : NSObject - it makes request and got response from server (singleton)
Then I got response I want to run MyMethod in LoginViewController from WebRequests.
I do it like here, but it not works:
WebRequests.h
#protocol WebRequestsDelagate <NSObject>
#required
- (void) MyMethod;
#end
#interface WebRequests : NSObject
...
#property (nonatomic, weak) id <WebRequestsDelagate> delegate;
WebRequests.m
#implementation WebRequests
//singleton
+ (WebRequests *)sharedInstance {
static dispatch_once_t p = 0;
__strong static id _sharedObject = nil;
dispatch_once(&p, ^{
_sharedObject = [[self alloc] init];
});
return _sharedObject;
}
- (id)init {
if (self = [super init]) {
LoginViewController * loginViewController = [[LoginViewController alloc] init];
self.delegate = loginViewController;
}
return self;
}
- (void) someMethod {
//here I got response
[self.delegate runThisMethod];
I do not move on in runThisMethod in LoginViewController.
Why does it not work?
UPDATE
#implementation LoginViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
// AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
return YES;
}
If that's your real code, then the loginViewController created in the [WebRequests init] method will be destroyed at the end of the if statement (i.e. pretty much straight away):
- (id)init {
if (self = [super init]) {
LoginViewController * loginViewController = [[LoginViewController alloc] init];
self.delegate = loginViewController;
}
return self;
}
I don't understand why you are creating view controllers in this method; it would be more normal to create the view controller outside of this class (through whatever method) and then register it as the delegate of the WebRequests object.
Okay, I'm a bit confused by your code but maybe you're looking for something like
WebRequests *webRequests = [WebRequests sharedInstance];
webRequests.delegate = self;
perhaps in LoginController's viewDidLoad.
I have two class files. ViewController and ChooseServerView. A user clicks a cell within the ViewController class which pushes to the ChooseServerView. When a user makes a selection in ChooseServerView the value of that cell gets passed to the delegate. Now, these two views are in front of a navigation controller, so in the ChooseServerView there is a back button. When the user clicks back I want to update the cell in the first view with the new value from the delegate, make sense?
ViewController.h
#import <UIKit/UIKit.h>
#import "ChooseServerView.h"
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, serverUserChoice>
{
NSString *testLocation;
}
#property (nonatomic, retain) NSString *testLocation;
#end
View Controller.m
#import "ViewController.h"
#import "ChooseServerView.h"
#import "AppDelegate.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize testLocation;
- (void)viewDidLoad
{
NSUserDefaults *sharedPref = [NSUserDefaults standardUserDefaults];
testLocation =[sharedPref stringForKey:#"defaultLocation"];
NSLog(#"Location Chosen: %#",testLocation);
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
#pragma mark - Table View Methods
- (void) userDidChoose:(NSString *) server {
testLocation = server;
NSLog(#"Test Location %#", server);
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; // Default is 1 if not implemented
{
return 2;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section; // fixed font style. use custom view (UILabel) if you want something different
{
switch (section) {
case 0:
return #"Choose Test Location:";
break;
case 1:
return #"Choose Test Type:";
default:
return #"Unknown";
break;
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
{
switch (section) {
case 0:
return 1;
break;
case 1:
return 1;
default:
return 0;
break;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
UITableViewCell *serverLocCell = [tableView dequeueReusableCellWithIdentifier:#"serverLocation"];
switch (indexPath.section) {
case 0:
serverLocCell.textLabel.text = testLocation;
serverLocCell.detailTextLabel.text = #"Change";
break;
case 1:
serverLocCell.textLabel.text = #"Speed Test";
serverLocCell.detailTextLabel.text = #"Change";
break;
default:
break;
}
return serverLocCell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.section) {
case 0:
[self performSegueWithIdentifier:#"toServerChoice" sender:self];
break;
case 1:
[self performSegueWithIdentifier:#"toTestType" sender:self];
break;
default:
break;
}
}
#end
ChooseServerView.h
#import <UIKit/UIKit.h>
#class ViewController;
#protocol serverUserChoice <NSObject>
#optional
- (void)userDidChoose:(NSString *) server;
#end
#interface ChooseServerView : UIViewController <UITableViewDataSource, UITableViewDelegate, serverUserChoice>
{
NSArray *serverSelection;
NSArray *tqServerSelection;
}
#property (nonatomic, retain) NSArray *serverSelection;
#property (nonatomic, retain) NSArray *qServerSelection;
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property(retain) NSIndexPath* lastIndexPath;
#property (nonatomic, assign) id <serverUserChoice> serverDelegate;
#end
ChooseServerView.m
#import "ChooseServerView.h"
#import "ViewController.h"
#import "AppDelegate.h"
#define totalSections 2
#define standardSection 0
#define qualitySection 1
#interface ChooseServerView ()
#end
#implementation ChooseServerView;
#synthesize serverSelection;
#synthesize qServerSelection;
#synthesize lastIndexPath;
#synthesize serverDelegate;
- (void)viewDidLoad
{
serverSelection = [[NSArray alloc] initWithObjects:#"Chicgo, IL",#"London, UK",#"San Jose, CA",#"Washington, DC", nil];
qServerSelection = [[NSArray alloc] initWithObjects:#"Chicgo, IL (Q)",#"London, UK (Q)",#"San Jose, CA (Q)",#"Washington, DC (Q)", nil];
[super viewDidLoad];
}
#pragma mark - Table View Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; // Default is 1 if not implemented
{
return totalSections;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section; // fixed font style. use custom view (UILabel) if you want something different
{
switch (section) {
case standardSection:
NSLog(#"Std Heading Set");
return #"Standard Test Locations:";
break;
case qualitySection:
NSLog(#"Qual Heading Set");
return #"Quality Test Locations:";
break;
default:
NSLog(#"Section Count Error");
return #"Section Count Error";
break;
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
{
if (section == 0) {
NSLog(#"Std Loc Set");
return [serverSelection count];
}
else {
NSLog(#"Quality Loc Set");
return [qServerSelection count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
UITableViewCell *serverLoc = [tableView dequeueReusableCellWithIdentifier:#"serverSelection"];
switch (indexPath.section) {
case standardSection:
serverLoc.textLabel.text = [self.serverSelection objectAtIndex:indexPath.row];
break;
case qualitySection:
serverLoc.textLabel.text = [self.qServerSelection objectAtIndex:indexPath.row];
break;
default:
break;
}
return serverLoc;
}
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellvalue;
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
cellvalue = cell.textLabel.text;
[serverDelegate userDidChoose:cellvalue];
NSLog(#"Cell Selected is %#",cellvalue);
[cell setSelected:FALSE animated:TRUE];
}
#end
I can see the correct value gets passed to the delegate, I just don't know how to "call" that delegate/method when going back using the automatic back button implemented by the nav controller.
Any ideas would be great.
As per answer below:
Added to my ViewController.h
#property (nonatomic, weak) IBOutlet UITableView *tableView;
Added to my ViewController.m
-(void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.tableView reloadData];
}
Still no joy at this stage. First cell fails to update upon pressing the back button as provided by the navigation controller.
Looks like you are almost there.
I think the issue is that your UITableView is not being reloaded to represent the updated value of testLocation. I don't see a reference to the UITableView that is being managed by your ViewController, first add an outlet to ViewController.m to point to this table view.
Then, add the following in your ViewController.m
-(void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.tableView reloadData];
}
You also need to make sure you set your ViewController as the delegate of ChooseServerViewController. (You should rename ChooseServerView.m to ChooseServerViewController.m for clarity, as it's a view controller subclass- I've referred to it as such below)
You can set the delegate by adding a prepare for segue method in ViewController.m - something like:
(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
ChooseServerViewController *viewController = (ChooseServerViewController *)segue.destinationViewController;
viewController.serverDelegate = self;
}
I would also look into using UITableViewController for these two controller classes, since it appears that's the type of functionality you are looking for.
I'm sure I'm missing something in a small iPhone program I'm trying to write, but the code is simple and it compiles without any errors and so I fails to see where the error is.
I've set up a NSMutableDictionary to store students' attributes, each with a unique key. In the header file, I declare the NSMutableDictonary studentStore:
#interface School : NSObject
{
#private
NSMutableDictionary* studentStore;
}
#property (nonatomic, retain) NSMutableDictionary *studentStore;
And of course in the implementation file:
#implementation School
#synthesize studentStore;
And I want to add an object into the dictionary:
- (BOOL)addStudent:(Student *)newStudent
{
NSLog(#"adding new student");
[studentStore setObject:newStudent forKey:newStudent.adminNo];
return YES;
}
class Student has the attributes:
#interface Student : NSObject
{
#private
NSString* name; //attributes
NSString* gender;
int age;
NSString* adminNo;
}
where newStudent has the values:
Student *newStudent = [[Student alloc] initWithName:#"jane" gender:#"female" age:16 adminNo:#"123"];
But when I look up the dictionary:
- (void)printStudents
{
Student *student;
for (NSString* key in studentStore)
{
student = [studentStore objectForKey:key];
NSLog(#" Admin No: %#", student.adminNo);
NSLog(#" Name: %#", student.name);
NSLog(#"Gender: %#", student.gender);
}
NSLog(#"printStudents failed");
}
It fails to print the values in the table. Instead, it prints the line "printStudents failed".
I guess this's quite basic, but since I'm new to iOS programming I'm a bit stumped. Any help will be appreciated. Thanks.
Your studentStore instance variable is a pointer to an NSMutableDictionary. By default, it points to nil, meaning it doesn't point to any object. You need to set it to point to an instance of NSMutableDictionary.
- (BOOL)addStudent:(Student *)newStudent
{
NSLog(#"adding new student");
if (studentStore == nil) {
studentStore = [[NSMutableDictionary alloc] init];
}
[studentStore setObject:newStudent forKey:newStudent.adminNo];
return YES;
}