Passing String through Segue - ios

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 :)

Related

Objective-C NSMutableArray only returning one item

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.

How to keep objects in NSMutableArray?

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.

Objective-C issue with Segue

I have this Segue here:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
//NSDate *object = self.objects[indexPath.row];
NSString *strPOIndex = [self.tableData[indexPath.row] valueForKey:#"POIndex"];
LHPurchaseOrderDetail *controller = (LHPurchaseOrderDetail *)[[segue destinationViewController] topViewController];
[controller setDetailItem:strPOIndex];
controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
controller.navigationItem.leftItemsSupplementBackButton = YES;
}
}
and what I am trying to do with it is pass strPOIndex to setDetailItem in my detail controller from my master controller.. but when I run this, I get an error:
-[LHPurchaseOrderMaster setDetailItem:]: unrecognized selector sent to instance 0x156cce80
I dont understand why this is happening, is it an issue with my storyboard? or my master controller or detail controller? Here is my Detail Controller:
.h:
#import <UIKit/UIKit.h>
#interface LHPurchaseOrderDetail : UIViewController
#property (strong, nonatomic) IBOutlet UINavigationBar *NavBar;
#property (strong, nonatomic) id detailItem;
#property (weak, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
#end
.m:
#import "LHPurchaseOrderDetail.h"
#interface LHPurchaseOrderDetail ()
#end
#implementation LHPurchaseOrderDetail
- (void)setDetailItem:(id)newDetailItem {
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
}
- (void)configureView {
// Update the user interface for the detail item.
if (self.detailItem) {
self.detailDescriptionLabel.text = [self.detailItem description];
}
}
- (void)viewDidLoad {
[super viewDidLoad];
[self configureView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end
Master Controller:
.h
#import <UIKit/UIKit.h>
#import "ShinobiDataSource.h"
#import "PopupGenerator.h"
#class LHPurchaseOrderDetail;
#interface LHPurchaseOrderMaster : UITableViewController<UIPopoverControllerDelegate, UIPickerViewDelegate>
#property (strong, nonatomic) IBOutlet UIButton *communityBtn;
#property (strong, nonatomic) IBOutlet UIButton *lotBtn;
#property (strong, nonatomic) IBOutlet UIButton *goBtn;
- (IBAction)communityBtnPressed:(id)sender;
- (IBAction)lotBtnPressed:(id)sender;
- (IBAction)goBtnPressed:(id)sender;
#property(nonatomic, retain) NSArray * tableData;
#property (strong, nonatomic) LHPurchaseOrderDetail *purchaseOrderController;
#end
Your error is this:
-[LHPurchaseOrderMaster setDetailItem:]: unrecognized selector sent to instance 0x156cce80
so it seems that somewhere in your LHPurchaseOrderMaster class you're trying to access and set the detailItem property as if it would be a part of LHPurchaseOrderMaster but because it doesn't exist there, you get an unrecognized selector error.
Edit
You should check for three things:
In Interface Builder check that the segue from LHPurchaseOrderMaster ViewController is to an UINavigationController that embeds the LHPurchaseOrderDetail ViewController as the first view controller in its stack.
Check the Class name returned by [segue destinationViewController]topViewController] like this:
id obj = [segue destinationViewController]topViewController];
NSLog(#"%#", NSStringFromClass([obj class]));
The class name should be LHPurchaseOrderDetail. If it's not, then you have a problem in your Storyboard where more than certainly you've connected the segue wrong.
Check your LHPurchaseOrderMaster class for any code that tries to access the "detailItem" property as if it would be part of this class.
It seems that the property you are trying to access is not accessible (wrong retrieved object).
Have you tried to use instead of
LHPurchaseOrderDetail *controller = (LHPurchaseOrderDetail *)[[segue destinationViewController] topViewController];
Something like
LHPurchaseOrderDetail *controller = (LHPurchaseOrderDetail *)[[segue destinationViewController] viewControllers][0];
I had sometimes the same your issue.
Set your detailItem not to NSString. Not to id. The problem is here,
self.detailDescriptionLabel.text = [self.detailItem description];
In configureView method change the code as follow,
- (void)configureView {
// Update the user interface for the detail item.
if (self.detailItem) {
self.detailDescriptionLabel.text = self.detailItem;
}
}
Don't forget to change this as well,
- (void)setDetailItem:(NSString *)newDetailItem {
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
}

Passing Data Through ViewControllers Not Working

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;
}

Issues passing JSON value through prepareForSegue

I have a simple app which connects to a web server and the web server returns a JSON value.
I am trying to send the JSON value from ViewController1 to "linkController", however when I send the sender over to ViewController2 the sender value is null?
Here is my code:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"linkControllerSegue"]) {
linkController *lc = [segue destinationViewController];
lc.introString = sender;
}
}
This is part of my linkController.h file:
#interface linkController : UIViewController
{
// succes view outlets
IBOutlet UILabel *short_url;
IBOutlet UILabel *full_url;
UIDataDetectorTypes *json;
}
#property (weak, nonatomic) NSDictionary *introString;
And my linkController.m file:
#synthesize introString;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"%#", introString);
}
The segue is being called through the code:
[self performSegueWithIdentifier:#"linkControllerSegue" sender:nil];
The NSLog in the viewDidLoad method returns: (null).
Is there anything I am doing wrong?
Many Thanks,
Peter
Try:
lc.introString = short_url.text;
instead of:
lc.introString = sender;

Resources