Ok so I am trying to pass data from one view controller to another via the following code but its not working and I have no idea why.
In my ViewController.m I have imported ViewControllerTwo.h and declared ViewControllerTwo:
#import "ViewController.h"
#import "ViewControllerTwo.h"
#interface ViewController ()
#end
#implementation ViewController
{
ViewControllerTwo *settings;
}
#synthesize blockSizeLB;
#synthesize wpmLB;
#synthesize textTV;
#synthesize slider;
#synthesize stepper;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//sets label to corresponding value
wpmLB.text = [NSString stringWithFormat:#"WPM: %#", [[NSNumber numberWithInt:slider.value] stringValue]];
//configure stepper and its label to default values of 1
stepper.value = 1;
blockSizeLB.text = [NSString stringWithFormat:#"Block Size: %#", [[NSNumber numberWithInt:stepper.value] stringValue]];
//sets properties for next ViewController
settings = [[ViewControllerTwo alloc] init];
settings.timerValue = 60 / slider.value;
settings.text = textTV.text;
settings.blockCount = stepper.value;
}
In ViewControllerTwo.h I have:
#property (nonatomic) float timerValue;
#property (nonatomic) NSString * text;
#property (nonatomic) int blockCount;
Later on in the ViewController.m I need to change the properties defined in ViewControllerTwo:
Method from ViewController.m. This is also done earlier in my viewDidLoad to set the default values of the properties:
- (IBAction)sliderSlide:(id)sender
{
//event when the slider value is changed
//rounds value to nearest increment of 5
int increment = 5 * floor(((int)slider.value/5)+0.5);
[slider setValue:increment animated:YES];
//changes WPM: 0 label text
wpmLB.text = [NSString stringWithFormat:#"WPM: %#", [[NSNumber numberWithInt:increment] stringValue]];
//sets properties for next ViewController
settings.timerValue = 60 / slider.value;
}
I try to test if this is successful by calling a method in ViewControllerTwo.m that logs its property blockCount via NSLog. The output however is (null) meaning I was unsuccesful in passing the data from ViewController.m to ViewControllerTwo
If you are using segues, you should be doing this inside of:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
Then name your segue, then do something like this:
if([segue.identifier isEqual: #"segue_From_1_To_2"])
{
ViewControllerTwo *vc2 = segue.destinationViewController;
vc2.timerValue = 123.45;
vc2.text = #"whatever";
vc2.blockCount = 1;
}
You can create a custom initializer in your viewControllerTwo. name it initWithTimerValue:
- (id)initWithTimerValue:(CGFloat)timerValue
{
self = [super init];
if (self) {
self.timerValue = timerValue;
}
return self;
}
Related
I am trying to print out a list of objects in my NSMutableArray via NSLog, but for some reason, it is appearing to be null. Basically, I have a to-do list that when the user enters a new string to add to the tableview, it will also add that item to the NSArray so I can save it to the device.
AddToDoItemViewController.m
#import "AddToDoItemViewController.h"
#import "ToDoItem.h"
#interface AddToDoItemViewController ()
#property (weak, nonatomic) IBOutlet UITextField *textField;
#property (weak, nonatomic) IBOutlet UIBarButtonItem *saveButton;
#end
#implementation AddToDoItemViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.toDoItem.itemList = [[NSMutableArray alloc] init];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
if (sender != self.saveButton) return;
if (self.textField.text.length > 0) {
self.toDoItem = [[ToDoItem alloc] init];
self.toDoItem.itemName = self.textField.text;
self.toDoItem.completed = NO;
NSLog(#"Trying to add to array: %#", self.toDoItem.itemName);
[self.toDoItem.itemList addObject:self.toDoItem.itemName];
NSLog(#"Array contents: %#", self.toDoItem.itemList);
}
}
#end
AddToDoItemViewController.h
#import <UIKit/UIKit.h>
#import "ToDoItem.h"
#interface AddToDoItemViewController : UIViewController
#property ToDoItem *toDoItem;
#end
ToDoItem.h
#import <Foundation/Foundation.h>
#interface ToDoItem : NSObject
#property NSString *itemName;
#property BOOL completed;
#property (readonly) NSDate *creationDate;
#property NSMutableArray *itemList;
#end
Now from my AddToDoItem.m file, when I use NSLog to try to output the Array I get this:
2016-02-24 01:04:49.668 ToDoList[4025:249117] Trying to add to array: ok
2016-02-24 01:04:49.669 ToDoList[4025:249117] Array contents: (null)
**** The 'ok' was the text I entered *****
You did not initialise the array before adding to it, add self.toDoItem.itemList = [NSMutableArray new];
Edit:
oh i see you added self.toDoItem.itemList = [[NSMutableArray alloc] init]; in the viewDidLoad, but this is not the right place to put it, it should be after self.toDoItem = [[ToDoItem alloc] init]; or inside the init method of ToDoItem
First, you need create an init method at ToDoItem.m
- (id)init {
self = [super init];
if (self) {
// Any custom setup work goes here
self.itemList = [[NSMutableArray alloc] init];
}
return self;
}
then run your project again.
You are initialising the Array( itemList ) before ToDoItem is initialised, so initialised array remains nil. So, it cannot store any object.
Modify code as below,
self.toDoItem = [[ToDoItem alloc] init];
self.toDoItem.itemList = [[NSMutableArray alloc] init];
you can add above lines of code either at viewDidLoad or at Segue Method
hope it helps you.
There are two view controllers.One to add items,the other one to display(table view).All items are stored in an NSMutableArray.But every time I unwind to add item and when I go back to the table view, there is only the newest item left.
Code:
- (void)viewDidLoad {
[super viewDidLoad];
[self addData];
}
- (void)addData {
if (!self.items) {
self.items = [[NSMutableArray alloc] init];
}
[self.items addObject:self.textFromFirst];
}
// textFormFirst is an NSString which received from the previous view controller
add view controller
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
UINavigationController *nav = [segue destinationViewController];
SecondController *second = [nav.viewControllers objectAtIndex:0];
second.textFromFirst = [self getText]; // get inputed string
self.aTextField.text = #"";
}
You can share an NSMutableArray between your two view controllers. Just use a property:
MainViewController:
// .m
#interface MasterViewController ()
#property (nonatomic, strong) NSMutableArray *items;
#end
#implementation MasterViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.items = [NSMutableArray array];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"ShowDetail"]) {
DetailViewController *controller = (DetailViewController *)[segue destinationViewController];
controller.items = self.items;
controller.textFromFirst = #"This is a test";
}
}
#end
AddViewController:
// .h
#interface DetailViewController : UIViewController
#property (nonatomic, copy) NSString *textFromFirst;
#property (nonatomic, strong) NSMutableArray *items;
#end
// .m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self addData];
}
- (void)addData {
[self.items addObject:self.textFromFirst];
}
These is a sample project: https://www.dropbox.com/s/ymum4zivgi0z688/TestUnwindSegue.zip?dl=0
I do not know why are you using array in AddViewController. Maybe you are prefer use unwind segue, like so:
// MainViewController.m
- (IBAction)saveItem:(UIStoryboardSegue *)segue {
DetailViewController *detailVC = segue.sourceViewController;
[self.items addObject:detailVC.textFromFirst];
}
In the case, you don't need to share an NSMutableArray to AddViewController.
How are you persisting the NSMutableArray between view controllers? If you need to persist one array across your entire application I would suggest you use a singleton. A singleton is an object that each instance has only 1 memory address, thus is always the same object. You could accomplish this by doing the following:
1) Press CMD+N and select "Cocoa Touch Class" / subclass NSMutableArray
2) Go to that class' .m file and add the singleton in init
static YourNSMutableArray *highlander;
#implementation YourNSMutableArray
- (instancetype)init {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
highlander = [super init];
});
return highlander;
}
3) Now whenever you create a new instance in any of your view controllers like this
if (!self.items) {
self.items = [YourNSMutableArray new];
}
[self.items addObject:self.textFromFirst];
self.items will always have the stored self.textFromFirst because any YourNSMutableArray you create in your app will always be the same object.
I have a levelViewController:
.m
- (void)viewDidLoad {
[super viewDidLoad];
double delayTimeInSeconds = 2;
dispatch_time_t popTimeDelay = dispatch_time(DISPATCH_TIME_NOW, delayTimeInSeconds * NSEC_PER_SEC);
dispatch_after(popTimeDelay, dispatch_get_main_queue(), ^(void){
//code to be executed after delay
GameViewController *level1 = [self.storyboard instantiateViewControllerWithIdentifier:#"gameViewController"];
level1.CARDS_PER_ROW = 6;
level1.gameModel.NUMBER_OF_PAIRS = 3;
[self presentViewController:level1 animated:NO completion:nil];
});//code to be executed after delay end
}
ok, he presents now the GameViewController with level1. The CARDS_PER_ROW is declared in GameViewController.h
.h
#import <UIKit/UIKit.h>
#import "GameModel.h"
#interface GameViewController : UIViewController
#property (nonatomic) GameModel *gameModel;
#property (nonatomic) int CARDS_PER_ROW;
#property (nonatomic) NSInteger newGame;
#end
.m
in my ViewDidLoad i have
self.gameModel = [[GameModel alloc] initWithNewGame:self.newGame];
And for my GameViewController i have my GameModel:
.h
#import <Foundation/Foundation.h>
#interface GameModel : NSObject
#property (nonatomic) int NUMBER_OF_PAIRS;
-(id) initWithNewGame: (NSInteger)newGame;
#end
.m
-(NSMutableArray *) createNewDeck {
NSMutableArray *cardDeck = [NSMutableArray array];
for (int i = 0; i < _NUMBER_OF_PAIRS; i++) {
[cardDeck addObject:[[CardModel alloc] initWithValue:i]];
[cardDeck addObject:[[CardModel alloc] initWithValue:i]];
}
return cardDeck;
}
Ok. My Problem is:
I CAN passing CARDS_PER_ROW. If i define NUMBER_OF_PAIRS ( #define NUMBER_OF_PAIRS = x; ) it works. But i CANT passing my NUMBER_OF_PAIRS data, and i don't know why. The Screen is empty with this Code I've posted.
The problem is that gameModel is nil at that point. The fact that you have instantiated a controller doesn't mean that its view is also loaded, the view will be lazy-loaded at first access. So, what you can do is to move the gameModel initializer to the controller's initializer (-initWithCoder in case of a nib/storyboard instantiation)
I'm trying to pass a NSMutableString through a segue.
The mutableString is a title from an MKPolygon.
I've done the mutableString like this: self.titleString = [[NSMutableString alloc] initWithString:polygon.title];
I'm not sure how to segue the String:
I've got this now:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"PickerViewController"])
{
NSLog(#"delegated");
//Get the new view controller using [segue destinationViewController].
PickerViewController *vc =[segue destinationViewController];
vc.titleString = titleString;
}
}
I get an error with vc.titleString = titleString;. Not sure how to set the String in the PickerViewController segue.
Error: Property 'titleString' not found on object of type 'PickerViewController *'
The PerformSegueWithIdentifier is this Method:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
//this would be the yes button or cancel
if (buttonIndex == 0 ){
NSLog(#"ButtonIndex Okay");
}
if (buttonIndex == 1) {
[self performSegueWithIdentifier:#"PickerViewController" sender:self];
}
}
I do know how to segue an object, but with Strings I don't get my mind to it.
Help would be really appreciated!
Update 1:
I've imported the PickerViewController.h in the ViewController.h file.
I've changed the vc.titleString = titleString; with vc.titleString = self.titleString;
I've added a #property (strong,nonatomic) NSMutableString *titleString; to the PickerViewController.h
No luck.
Update 2:
Tried an other way to segue the String: [(PickerViewController *)[segue destinationViewController] setTitleString:self.titleString];
Got the error: No visible #interface for 'PickerViewController' declares the selector 'setTitleString:'
ViewController.h file:
#property (strong, nonatomic) NSMutableString *titleString;
ViewController.m file:
#synthesize titleString;
self.titleString = [[NSMutableString alloc]init];
PickerViewController.h file:
#property (strong, nonatomic) NSMutableString *titleString;
PickerViewController.m file:
#synthesize titleString;
self.titleString = [[NSMutableString alloc]init];
Still seems like it doesn't recognises the titleString.
Update 3:
Still no luck with segueing the string.
Maybe it has something to with this:
The NSMutableString is being used in a loop. The loop checks if there is an GPS, annotation or a touch is inside a MKPolygon. Each polygon has it's own color, which is named in the polygon.title: See code below*. So the String saves the 'selected' polygon title. See the loop below:
One of the Polygons:
CLLocationCoordinate2D roodPoly[2];
roodPoly[0] = CLLocationCoordinate2DMake(52.372445351278294, 4.876454472541809);
roodPoly[1] = CLLocationCoordinate2DMake(52.37288748990477, 4.878369569778442);
MKPolygon *roodpoly = [MKPolygon polygonWithCoordinates:roodPoly count:2];
roodpoly.title = #"red";
[myMapView addOverlay:roodpoly];
A little bit of the loop:
if(CGPathContainsPoint(mpr , NULL, mapPointAsCGP, FALSE)){
NSLog(#"Coordinate %f,%f is in polygon %#", tapCoord.latitude, tapCoord.longitude, polygon.title);
self.titleString = [[NSMutableString alloc] initWithString:polygon.title];
self.subtitleString = [[NSMutableString alloc] initWithString:polygon.subtitle];
alertView = [[UIAlertView alloc]initWithTitle:#"Found it" message:subtitleString delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Stel notificatie in", nil];
[alertView show];
NSLog(#"The color of the Polygram is: %#", titleString);
}
CGPathRelease(mpr);
}
}
}
I thought this could cause the problem for not finding the String :(
On your "PickerViewController.h" should look like:
#import <UIKit/UIKit.h>
#interface PickerViewController : UIViewController
#property (strong,nonatomic) NSMutableString * titleString;
#end
And on your "ViewController.m" file:
#import "ViewController.h"
#import "PickerViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
[(PickerViewController *) [segue destinationViewController] setTitleString:self.titleString];
}
#end
It is Working fine here..
Hope it helps :)
So I have two classes. When press the save button, it will pass down the value from self.screen.text by addItem method to the totalArray in class 2. If I try to NSLog in the #implementation of addItem method, then it will give out the correct output but If I do it in viewDidLoad, the output is null. How can I save the value passing from class1 to property of class2 permanently? Thank you. The class2 in a subclass of UITableViewController
Class 1 #interface
//class1.h
#import class2.h
#interface class1 : superclass {
}
- (IBAction)buttonSave:(id)sender;
Class1 #implementation
//class1.m
#interface class1 ()
#end
#implementation class1 {
}
- (IBAction)buttonSave:(id)sender {
class2 *Obj = [[class2 alloc] init];
[Obj addItem:self.screen.text];
}
And class2 #interface
//class2.h
#import class2.h
#interface {
}
#property (strong, nonatomic) NSMutableArray *totalArray;
class2 #implementation
#interface class2 ()
#end
#implementation {
}
- (void) addItem:(id)item {
self.totalArray = [[NSMutableArray alloc] init]; //alloc & init
[self.totalArray addObject:item]; //add object to the total array
// NSLog(#"%#", self.totalArray); If I NSLog in within this method then everything works as expected.
}
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"%#", self.totalArray); //But in here the output is null. ???
}
I think that your problem is that you have use a different class2 object. The one that you had init in buttonSave, is not the one that you are displaying
add a property in class1.h
#property (nonatomic, strong) NSMutableArray *savedArray;
and modify buttonSave :
- (IBAction)buttonSave:(id)sender {
self.savedArray = [[NSMutableArray alloc] init];
[self.savedArray addObject:self.screen.text];
}
You are using a storyboard, then please try to add this in class1.h and add an identifier class2Segue to this segue in your storyboard :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"class2Segue"])
{
Class2 *tableController = (Class2 *)[segue destinationViewController];
tableController.totalArray = self.savedArray;
}
}
viewDidLoad is called after init so you array is nil here. Change your class2 init method to accept the item.
// In class2
-(id) initWithStyle:(UITableViewStyle)style andItem:(id)item {
self = [super initWithStyle:style];
if(self) {
self.totalArray = [[NSMutableArray alloc] init];
[self.totalArray addObject:item];
}
return self;
}
Your addItem will then look like,
- (void) addItem:(id)item {
//Just add, do not initialize again
[self.totalArray addObject:item];
}
The button action in class1 will now look like,
- (IBAction)buttonSave:(id)sender {
class2 *Obj = [[class2 alloc] initWithItem:self.screen.text];
//OR
//class2 *Obj = [[class2 alloc] initWithItem:UITableViewStylePlain andItem:self.screen.text];
}
Hope that helps!
Try to use like this...
- (IBAction)buttonSave:(id)sender
{
class2 *Obj = [[class2 alloc] init];
Obj.totalArray = [[NSMutableArray alloc] init]; //alloc & init
[Obj.totalArray addObject:self.screen.text];
NSLog(#"screen.text %#", self.screen.text); // -- check here it may be null----
NSLog(#"Obj.totalArray %#", Obj.totalArray);
}
#interface class2 ()
#end
#implementation {
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%#", self.totalArray); //But in here the output is null. ???
}
You can not ensure when your viewDidLoad method will call... so better pass the value to the init method and set there initWithText:(NSString*)text{}. Other wise try to call NSLog in viewWillAppear or viewDidAppear just for testing purpose. In iOS 7 now presentation of view-controllers is bit changed now.