I followed John Wordsworth tutorial (http://www.johnwordsworth.com/2011/10/adding-charts-to-your-iphone-ipad-app-using-core-plot/) to produce a line graph with CorePlot.
Later I decided to get some JSON data from a website so that I can use it for my graph.
All the url connection methods are performed in my ViewController.m file. And there I created an NSArray called indicator containing all the JSON data.
My problem is that all of the graph's parameters are defined in a separate NSObject class called SimpleScatterPlot.m where I would like to use the array of strings "indicator" (defined in ViewController.m) to customize the x-Axis labels.
What do I have to do so that I can use this JSON data array in SimpleScatterPlot.m?
I tried #import "ViewController.h" but it did not solve it.
Thanks in advance for any guidance you can give me.
Not sure if I am understanding it correctly, but I think you have not try to access the indicator nsarray from SimpleScatterView.m but to set there the value from ViewController.m.
1) Define a public NSArray in SimpleScatterView.m and synthesize it.
2) Instead of trying to gain access, use "prepareForSegue" in ViewControler.m to set indicator in the destinationSegueController.
3) In SimpleScatterView.m implement "-(void)setIndicator:(NSArray *)indicator" and update the GUI as needed.
Although the "Model - View - Controller" paradigm recommends not to use ViewControllers to perform communications and so on, but that is for another thread.
Create a property in Viewcontroller and synthesize it. Then pass the JSON data to the property.
To access the array in SimpleScatterView.m:
Viewcontroller *viewcontrol = [[ViewController alloc] init];
You can then access the array by using viewcontrol.indicator.
NSLog(#"%#",viewcontrol.indicator);
If I do not read incorrectly what you are trying to do, my guess is that you could appropriately use SimpleScatterView from within your UIViewController view (this is, assuming that SimpleScatterView is actually a UIView).
In this case, when your controller has downloaded its data, you could instantiate SimpleScatterView and display it by adding it to your view controller view.
... <data has been downloaded> ...
SimpleScatterView* scatterView = [[SimpleScatterView alloc] initWithFrame:...];
[self.view addSubview:scatterView];
When you initialize your SimpleScatterView, you could pass it a reference to the data array (say, in its custom init method, or using a property). e.g.:
SimpleScatterView* scatterView = [[SimpleScatterView alloc] initWithFrame:... andData:(NSArray*)...];
or:
scatterView.dataSet = <your_json_array>;
Of course, you have plenty of alternatives to this design. Specifically, I would mention:
the possibility of using a model class to handle all of your data, such that the controller writes the data to the model, while the plot view reads the data from it. The model could be implemented though a singleton in this case for ease of access;
the possibility of using a "dataSource" for your plot view: this would entail defining a protocol between the view and its datasource (e.g., a getData method); your view controller would play the role of the data source (in other words, instead of passing the array to the plot view as in above example, you would pass a reference to the controller and the view would access its data).
Related
Let's say I have a simple app that is loading data into a table view. It then allows you to view details (etc).
My table view controller on first load looks something like this below.
Notice I am not using an "property" declarations for these variables. Is this OK? Are there any disadvantages regarding the way memory is then handled?
#interface TblVC ()
{
MBProgressHUD *hudLoad; // new up loading while I go get data
NSMutableArray *results; // set to results after loading data
CLLocationManager *locManager; // get location in view load
}
#end
#implementation TblVC
{
}
- (void)viewDidLoad
{
// spin up the above variables here which can then be used in other methods inside view controller
}
Just use properties. There is absolutely no reason to use the old-style instance variables anymore.
Apple's documentation on properties goes into detail about the benefits. https://developer.apple.com/library/ios/documentation/cocoa/Conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html
An instance variable is unique to a class. By default, only the class and subclasses can access it. Therefore, as a fundamental principal of object-oriented programming, instance variables (ivars) are private—they are encapsulated by the class.
By contrast, a property is a public value that may or may not correspond to an instance variable. If you want to make an ivar public, you'd probably make a corresponding property. But at the same time, instance variables that you wish to keep private do not have corresponding properties, and so they cannot be accessed from outside of the class. You can also have a calculated property that does not correspond to an ivar…
Without a property, ivars can be kept hidden. In fact, unless an ivar is declared in a public header it is difficult to even determine that such an ivar exists.
A simple analogy would be a shrink-wrapped book. A property might be the title, author or hardcover vs. softcover. The "ivars" would be the actual contents of the book. You don't have access to the actual text until you own the book; you don't have access to the ivars unless you own the class.
I have an UIViewController in wich I imported a class:
#import "differenza.h"
and then I created an instance of that class when a button is pressed:
- (IBAction)ok:(id)sender {
differenza *classeDifferenza;
classeDifferenza = [[differenza alloc] init];
[classeDifferenza metodo];
}
As you can see, I also called a method.... now I don't have enough space in that UIViewController for the results of that method, so I need a new ViewController to show all the results... but I don't know how to recall results from that new ViewController, as I can not use the
classeDifferenza.variabile
way ....
This is something I did not really get already. In the past I used (thanks to your help: Setting up class instances in a multi view app (Objective C)) a "common class" where to store all data and all methods... but I don't think It's always the proper way... I feel like I am abusing that solution... or It's the right way to do what I described?
Thanks!
You can pass data with prepareForSegue check this topic
How to pass prepareForSegue: an object
You can send variable results like that
I am a beginner in terms of xcode and objective-c and I am currently building an app that reads xml Files and compares their values to textfield values.
I have 2 classes. The first one is my View Controller where my textfields are. The second class is where I iterate through my xml files.
I simply want to be able to access the textfield's text my XML iterator class.
It is important that I can save the text that has been entered in the textfield as a variable in my iterator class.
I attempted to do something like this, but it didn't work:
ViewController *viewcontroller = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
viewcontroller.string = self.myTextField.text;
Help would be greatly appreciated since I have had trouble with this for a long time now.
Let's return to the basics of MVC pattern (which stands for Model-View-Controller) — your view controller talks directly to your views and model (or any helpers, like XML iterator in our case). So most likely the right approach would be to give your XML iterator text values directly in your ViewController's implementation and update / reset XML iterator every time text field's value changes.
One way to implement this is to have a strong #property to your XML iterator in your ViewController class (create XML iterator instance once, then assign in to the property and use it later). Another common way is to implement your XML iterator as a singleton class.
It's hard to tell which option is better in your exact case (for example, you can also use protocols or even notifications). However, this general MVC-oriented approach described above works in most basic cases. For more, read about Model-View-Controller pattern — Apple Documentation is the right place to start.
I'll start by saying I'm new to Objective-C and iPhone but I have history in C++, Java, AS3, ...
I'm trying to build some sort of RSS Reader, and I have an array for all my feeds. How is the best approach to save new feeds to this array? I have a navigation based project, and I have an add button which pushes a viewController on top to enter new feed URL.
But how do I save this back to the array in my other ViewController? Do I need to research more into SQLLite? Or set some delegates? Or Core Data?
I prefer the singleton method myself but Apple recommends dependency injection i.e. passing a data model object from view controller to view controller as needed.
If you look at a Core Data utilizing template navigation project in Xcode, you can see how this works. The managedObject context is the data model and it is initialized and held by the app delegate. You can then access it two ways:
(1) Since the Application instances itself is a singleton, you can ask it for its delegate and then ask the delegate for its managedObjectContest property. So, in a view controller you would have a property managedObjectContext with a custom getter defined like:
(NSManagedObjectContext *) managedObjectContext{
if (managedObjectContext !=nil){
return managedObjectContext;
}
// this is basically applicationObject.delegate.managedObjectContext
self.managedObjectContext=[[[NSApplication sharedApplication] delegate] managedObjectContext];
return managedObjectContext
}
(2) Alternatively, whenever a view opens another view, it just sets the next view's managedObjectContext property to it's own. So that every view opens with a context. This is useful if you actually have multiple data objects for some reason.
If your just using an array or a custom data model class just substitute its name for the managedObjectContext in the code above.
Check out this question. I recommend using a singleton class and creating some listener pattern to signal when the data has changed (or just reload, always, before your view becomes visible).
You might want to store your feed items in memory by using the a singleton
Something similar to what is being used: Singleton shared data source in Objective-C
I used this 'tutorial' to bind my array called 'collection' to a NSTableview on my interface:
http://www.cocoadev.com/index.pl?NSArrayController
The interfacebuilder stuff isn't that hard. It becomes difficult when I try to actually show the data in my array into the view.
in my .h file:
#interface MyDocument : NSDocument
{
NSMutableArray *collection;
//other variables
}
and in my .m file:
#implementation MyDocument
#synthesize collection;
//quite some functions
inside one function (that works):
[collection addObject:fileName];
//some other functions
inside the init function:
collection = [[NSMutableArray alloc] init];
Now I guess the array is bound well to the interface and the tableview inside it, but ofcourse the tableview and its columns need to be filled in a specific way. Right now nothing shows after adding an item. with collection addObject:fileName function
Should I create a sub-Array as one item, filled with fields? And how should I bind these values/fields to the specific columns. (the fields are 'artist', 'title', etc)
I have already bound every column in Interface Builder to Array Controller with Controller key 'arrangedObjects' and Model Key Path 'artist','title',etc.
Please keep the explanation simple since I'm slowly starting to think I will never get this Array Controller thing... Objective-C doesn't seem that hard, but the binding which it needs is what I just don't get. Apple's examples are not sufficient to newbies
Typically to populate your data you'd use a dictionary (the key would be the keyPath, and object the data) for each row, or even better, create a class to represent the data and create a new instance for each row. Bindings can be a little tricky at first (if you're new to Cocoa get used to the data source methods first), but have a look at this tutorial and the examples here. Both contain samples you can download and examine exactly how the bindings is set up in Interface Builder.
Just mutating the array doesn't tell anything that the array has changed. You need to send KVO notifications for the mutation.
The right way to do this is to implement accessor methods for the property, then call your own accessors. In this case, you'll want to implement insertObjectInCollection:atIndex: and pass the length of the array as the index ([self insertObjectIntoCollection:fileName atIndex:[self countOfCollection], after also implementing countOfCollection).
When you implement accessors, then when an object binds to the property, Cocoa will wrap the accessors in KVO magic that will send the appropriate notifications for the mutation.