I'm creating an user setup account with 5 steps using storyboard. Each step have a ViewController: 1º)Input for Name, contact etc, 2º) Import photos, 3º)Input, etc 4º)more inputs 5º)Confirmation Page, if the user click "confirm" -> Get all the inputs and upload to Parse.
The only solution i get when i search online for this, is to create a func "Prepare for Segue" and pass the information...But for me, this doesnt make any sense:
If i had 1000 viewcontrollers, the first viewcontroller information will be passsed through all the 1000 viewcontrollers? Why not the nº1000 view controller getting all the information that was left behind? e.g: The viewcontroller nº50 dont need the information about the viewcontroller nº1... This is a nonsense.
Is there any other way to implement this?
Maybe there is a solution since i'm using Parse like when i do:
ParseClass["Name"] = textfield.text
It sends information to Parse and they hold it until i do something like SaveInBackground().
I'm trying to find a solution like this using viewcontrollers. Each viewcontroller send information to parse and hold the information until the "saveinbackground()" happens on Viewcontroller nº5.
Possible? thank you
Yes it is possible. You can use NSUserDefaults for that which will store your info into memory and once it is stored you can use it anywhere in your project.
Like you can store value with it this way:
NSUserDefaults.standardUserDefaults().setObject(yourObject, forKey: "yourKey")
Now you can retrive this info from any where with yourKey like this:
let yourInstance = NSUserDefaults.standardUserDefaults().objectForKey("yourKey")
And you can cast it's type as per your need.
For more Info read Apple Document for NSUserDefaults.
One more way to pass value from one view to another view without segue by using Class or Struct.
You can read more about Classes and Structures from Apple Documentation.
If our inputs are finite, create a model class with properties for it ex:
#interface UserDataInput : NSObject
#property (nonatomic)NSString *name;
#property (nonatomic)NSString *contactNumber;
....
blah blah bla
....
#end
then make it as a singleton class
#implementation UserDataInput
+ (instancetype)sharedInstance {
static dispatch_once_t onceToken;
static UserDataInput *sharedInstance = nil;
dispatch_once(&onceToken, ^{
sharedInstance = [[[self class] alloc] init];
});
return sharedInstance;
}
#end
Then set properties from a view controller on leaving that view controller like,
UserDataInput *sharedInput = [UserDataInput sharedInstance];
sharedInput.name = self.nameField.text;
etc....
In final view controller you can access these properties to upload to parse.
Try it.
let yourInstance = NSUserDefaults.standardUserDefaults().objectForKey("yourKey")
NSUserDefaults.standardUserDefaults().synchronize()
Related
My app has two views managed by a Tab Bar Controller. One of the views is Google Map (GMSMapView using their SDK) and the other is a TableView showing a list of the same data. The markers on the map are the same data in the TableView (just alternate presentations of the same data).
I fetch the data from an NSURLSessionDataTask. I'm wondering what is the best way to share that data between the two views. Obviously, I don't want to fetch the data twice for each view. But I'm not sure what is the best practice for making that shared data available/synched between the two views.
A similar question was asked but not answered here.
You can create a model class which holds the map related data in an array/dictionary/custom class objects. You can make this model class as a singleton(can be initialized only once). Both view controllers (i.e the map and table view) can refer to this model to populate date in different views now.
Model Class
-----------
#property (strong, nonatomic) MyCustomDataRepresentationObj *data;
+ (id)sharedModel {
static MyModelClass *sharedModel = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedModel = [[self alloc] init];
});
return sharedModel;
}
-(void)fetchMapDataWithCompletionBlock:(void(^)(id response, NSError *error)onComplete
{
// Check if data is available.
// Note: You can add a refresh data method which will fetch data from remote servers again.
if (!data) {
__weak MyModelClass *weakSelf = self;
// Make HTTP calls here, assume obj is returned value.
// Convert network response to your data structure
MyCustomDataRepresentationObj *objData = [MyCustomDataRepresentationObj alloc] initWith:obj];
// Now hold on to that obj in a property
weakSelf.data = objData;
// Return back the data
onComplete(objData, error);
} else {
onComplete(objData, nil); // Return pre fetched data;
}
}
Now in view controllers you would have to call the model class method which will inturn make the network call(if needed) and returns data in completion block.
View Controller 1
-----------------
-(void)viewDidLoad
{
// This is where the trick is, it returns the same object everytime.
// Hence your data is temporarily saved while your app is running.
// Another trick is that this can be accessed from other places too !
// Like in next view controller.
MyModel *myModelObj = [MyModel sharedModel];
// You can call where ever data is needed.
[myModelObj fetchMapDataWithCompletionBlock:^(id response, NSError *error){
if (!error) {
// No Error ! do whats needed to populate view
}
}];
}
Do the same in other view controller.
View Controller 2
-----------------
-(void)viewDidLoad
{
// Gets the same instance which was used by previous view controller.
// Hence gets the same data.
MyModel *myModelObj = [MyModel sharedModel];
// Call where ever data is needed.
[myModelObj fetchMapDataWithCompletionBlock:^(id response, NSError *error){
if (!error) {
// No Error ! do whats needed to populate view
}
}];
}
Note: I have just jotted down these lines of code here, there might be syntax errors. Its just to get the basic idea.
A UITabBarController act as a Container.
So from your 2 child ViewControllers, you can access the TabBarViewController with the property parentViewController.
So if you want to share the same data with your 2 child ViewControllers, you can fetch and store your data in your UITabBarController. And, from your UIViewControllers, you can access it like this
MyCustomTabBarController *tabBar = (MyCustomTabBarController*)self.parentViewController;
id data = tabBar.myCustomData;
Use Singleton Patterns create a singleton class and initialize singleton instance in your AppDelegate.m this way you can access your singleton class instance from your AppDelegate by using
How about a data fetching object? Make a new class that makes requests for your data bits and stores the results internally.
You then could get the data into your ViewController with a number of different methods:
Direct Reference Associate this object with each ViewController as a property on the ViewControllers before setting the viewControllers property on the Tab Bar Controller.
Your interface to this new class could include the set of fetched results, as well as a method (with a callback when the request finished perhaps) to tell the object to fetch more results.
Notification Center Your object could post notifications when it has more data, and just include a method to start requesting more data.
Delegate + Registration You could create a protocol for objects that want to get told about changes to the data set, make sure all of your necessary ViewControllers conform, and have a delegates NSArray property on your data fetching object. This is far more manual than Notification Center, but it's slightly easier if you need a very robust interface.
Needless to say, there are a lot of ways to handle this, but they all start with designating a class to do the specific task of fetching/storing your data.
Okay, so I was reading here declaring global variables in iPhone project and I noticed the line with this code: [[[UIApplication sharedApplication] delegate] myNSString];.
Basically, I want a user to input something in a text field on the flipside view, then have it stored in a variable which is accessed on the main view. Ideally, the main view would be able to just read the text field from the flipside view, but this seems to be impossible (I've spent several hours each day for the past few days scouring the web and various books for an answer about how to do this and no one seems to be able to give a definitive answer). Therefore, I'm resorting to using a global variable to tackle this.
Will the code that I printed above somehow allow me to do this? I've been trying to adapt it for the past hour, but have come up with nothing except No known instance method for selector 'myNSString' and I'm not quite sure what that means in this case.
Can someone please help me out? I feel like I can keep trying different things but without some sort of help, I'm just shooting in the dark here. Thank you!
You may want to think about using a singleton to hold your data if you're set on using a global variable. There's a good tutorial on singletons here: http://www.galloway.me.uk/tutorials/singleton-classes/ -basically it's a class that can be shared throughout the application and accessed/modified by different controllers. You'd be able to create a property on it, write to that property from the flip view, and then access that property from your main view.
#import "Singleton.h"
#implementation Singleton
#synthesize yourTextField;
#pragma mark Singleton Methods
+ (id)sharedManager {
static Singleton *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
- (id)init {
if (self = [super init]) {
yourTextField = #"";
}
return self;
}
You could call it in code by importing its header file and:
Singleton *mySingleton = [Singleton sharedManager];
the mySingleton object will have the text field attached. It can be accessed by:
mySingleton.yourTextField;
.h file:
#import <Foundation/Foundation.h>
#interface Singleton : NSObject
#property (nonatomic, strong) NSString *yourTextField;
+ (id)sharedManager;
#end
Singleton (remember about dispatch_once), static variables or NSUserDefaults. It really depends what you really need.
If you are using storyboards and just want to pass data between VC, then you can use "prepareForSegue" method (described here https://developer.apple.com/library/ios/documentation/uikit/reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instm/UIViewController/prepareForSegue:sender:).
Segue has "destinationController" property, so you can setup VC before showing it.
Class name MyData has 75+ properties that are needed in throughout 7 Scenes.
Currently, I pass the the instance of MyData file with the code below:
in SceneOne:
MyData *myData = [[MyData alloc]init];
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UIViewController *destinationViewController = segue.destinationViewController;
SceneTwo *sceneTwo = [destinationViewController isKindOfClass:[SceneTwo class]] ? (SceneTwo*)destinationViewController : nil;
sceneTwo.myData = self.myData;
}
This allows me to access any properties as myData.anyProperty
When the 7th Scene is dismissed, I set myData = NULL, and the app returns to SceneOne and a new instance of MyData is initialized.
I'm trying to accomplish above via sharedInstance.
MyData.h
#import <foundation/Foundation.h>
#interface MyData : NSObject {
#property (nonatomic, retain) NSString *someProperty;
// 74 other properties
+ (id)sharedData;
#end
MyData.m
#import "MyData.h"
#implementation MyData
#synthesize someProperty;
+ (id)sharedData {
static Mydata *sharedData = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedData = [[self alloc] init];
});
return sharedData;
}
#end
Question 1: Will the code above work to access the same instance with the code below in any of the Scenes:
MyData *myData = [MyData sharedData];
Question 2: Can I still access the files as myData.anyProperty ?
Question 3: How do I trigger a new instance of MyData and delete the current instance?
Question 4: I'm downloading a myData file off the web that's a duplicate of MyData class but the properties contain data, and I want Singelton to provide a new instance with the data from the downloaded file, what would be the code for that? i.e myData = [newDownloadedFile copy];
Question 5: Is there an advantage of using Singleton Method Vs. my current method?
Yes
Yes
You don't. Why do you believe this is necessary? Can you instead add a reset method to MyData?
You shouldn't mix the singleton pattern with a multiple-instance usage case. If you truly want a singleton, think about adding an additional layer to your data set. For example, you may have a local data and remote data configuration. If this is what you want, you may have to change the interface (header) of MyData to make this possible.
A singleton is a single instance of a class across a process. When you want to access the same collection of data from multiple locations in your code, a singleton object is one way you can accomplish this. Otherwise you need to instantiate an object and pass its address to all interested classes so they are each accessing the same instance. That's an oversimplification but I believe it addresses your question.
Regarding your comment for number 3, if you have a singleton, you don't want to reset the data for the entire app if you simply don't need the data in one place anymore. So consider the impact that would have. If you no longer need the MyData object, simply don't use it anymore. Singleton objects typically persist for the lifetime of an app, so it is not common to release/dispose of the object.
For number 4, say you currently have a property called player with a method declaration like this:
- (Player *)currentPlayer;
If you have multiple configurations available, you would add a parameter to your method interface and implementation like this:
- (Player *)currentPlayerForConfiguration:(NSInteger)configuration;
You could decide to use a number, string, or something else to differentiate between different configurations of your data. If you use a number, 0 could be local, 1 could be remote, 2 could be either (for example, check local data first, and if not there, then check remote). If you only have two options, you could use a BOOL and define your method like this:
- (Player *)currentPlayerUsingLocalData:(BOOL)useLocalData;
I have a UIViewController class and a UITableViewController class. Within the UIViewController class I have an NSMutableArray.
I now have the issue of how to load data into my table view, a separate class, I must access the NSMutableArray I used to populate the previous UIViewController class.
I tried using a delegate to access the array in the UIViewControllerClass however the array had "0 objects" and was NULL
I would appreciate some guidance in the right direction here.
You could have one view controller hold a reference to the other view controller and query the public NSMutableArray on it for data. Aaron suggested this and it might be your best solution.
Or.. you have multiple view controllers trying to access the same set of data. Potentially you have other classes which will want to access this data also. You might want to consider pulling the data out of the view controller and storying it in a neutral location. You could store it in the AppDelegate and then reference the app delegates from any place you need it.
id<UIApplicationDelegate> appDelegate = [UIApplication sharedApplication].delegate;
NSMutableArray *myData = appDelegate.data;
You could also consider pulling all the logic of your data and the data itself into a separate class and use a Singleton It would allow you to access/manipulate the data fairly easy from anywhere.
The last 2 methods would insulate data from user interface controller objects and prevent the need from potentially unrelated objects needing to hold references to one another. Used properly it will reduce code complexity and mage future changes easier to manage.
Create an NSMutableArray property on your UITableViewController class like so:
#interface CustomTableViewController : UITableViewController
#property (strong, nonatomic) NSMutableArray *dataFromOtherClass;
#end
And then when you transition, perhaps like this, you can set the dataFromOtherClass property:
CustomTableViewController *controller = [[CustomTableViewController alloc] initWithNibName:#"CustomTableViewController" bundle:nil];
controller.dataFromOtherClass = myNSMutableArrayData; // <-- Set data like this
[self.navigationController controller animated:YES];
// Or ...
[self presentViewController:controller animated:YES];
// Etc...
I am writing the iPhone application and I would like to ask about the the passing parameters in Objective-C.
I create 2 view controller. In the first one, I have a button, when a user press the button, it will call the -(IBAction) pressButton (user-defined), and after 5-6 second (have to process and retrieve the data in the NSMutableArray *), it will display a table. However, I don't know how to pass the NSMutableArray to the table class. Can I do this?
// situation
// ---------------------------------------------
// In MyViewController.m
// class variable
NSMutableArray * arr;
- (IBAction) pressButton: (id)sender {...}
// I retrieve the data and store in the arr
// In TableView.m
// I want to pass the arr to here and use
I know how to create the table, but I don't know how to pass the parameters from a class (MyViewController.m) to another class (TableView.m).
In TableView.h, declare a method:
- (void)doWhateverWithArray: (NSArray *)anArray;
In TableView.m, implement the method to do whatever you need it to do.
In MyViewController.m, near the top of the file (outside of #implementation ... #end) write #import "TableView.h"
Send -doWhateverWithArray: to your table view when necessary.
Function calls are a fundamental part of procedural programming languages like C; message dispatches (AKA method calls) are a fundamental part of object-oriented programming languages like Objective-C.
The nature of this question suggests you're just starting to get into programming (if I'm wrong, please don't take this as an insult--it's not.) I'm sure folks can recommend any number of introductory texts to C or Objective-C, but I'd go further if I were in your shoes.
If available to you, I recommend that you take college-level programming courses, or even enroll in a computer science degree at the university level if you have the time and dedication. :)
In your TableView ViewController create NSMutableArray like this
IBOutlet NSMutableArray *PassedArray;
#property(nonatomic,retain) NSMutableArray *PassedArray;
#synthesize PassedArray;
[PassedArray release];
Now you can pass NSMutableArray value from your Myviewcontroller to tableviewcontroller using this
tableviewcontroller *objInstance = [[tableviewcontroller alloc]initWithNibName:#"tableviewcontroller" bundle:nil];
objInstance.PassedArray = NSMutableArray;//Here you declare your passed NSMutableArray
[self.navigationController pushViewController:objInstance animated:YES];
[objInstance release];
Another method is Declare NSMutableArray *yourArray is global in MyViewController.h and extern those variables in tableviewcontroller.m like this
extern NSMutableArray *yourArray;