JSON - Php/SQL iPhone APP Questions/Help - iphone

Hey group, first time posting here
I am somewhat new to the JSON/PHP/mySQL world, but been around iPhone designing for the past few years, though this topic of conversation is a while new area I am entering.
I have done JSON iPhone examples that allow me to create a UITableView and display the JSON data into the TableViewCells (CustomCells) and displays the data (NSDictionary)into UILabels
The problem I am having now, is that I want an APP that displays this information from the JSON into just a couple of UILabel's on a regular UIViewController and not a UITableView
any help would greatly be appreciated,
the example I used and learned for JSON and UITABLE was from http://tempered.mobi/%20
I used that example from my app, but incorporated a few other things like CUSTOM cells
however now when the USER selects the specific CELL I want it to load specific data from another JSON file, and cannot get it to load in a UILabel or UITextView in a UIViewController
HELP :-)

Not sure if I completely understand your query, when the user clicks on a table cell you want the app to do a request for data in JSON format and display it in labels on a view? correct?
If so, then I'd modify the didSelectRowAtIndexPath method. Use the index to determine which JSON request to fire, load the results into object/array/dictionary and then set the labels text from this data source.
Apologizes if I mis-understood your question.

Here is my coding to it, this is the XIB that is loaded once the TABLEViewCell is selected, i apologize in advanced for the formatting, I dont know why it is not coming out properly as I am simply copying and pasting from Xcode
.h File, all I added was
IBOutlet UILabel *homeTeam;
IBOutlet UITextView *homeTeam2;
IBOutlet UILabel *awayTeam;
NSArray *rows;
}
#property (retain, nonatomic) NSArray *rows;
(added note: I obviously hooked up the UILabels and UIText View to my labels and text view in that specific XIB) and have tested using the homeTeam.text = #""; (in the Implementation file)to make sure they are functioning properly
.m file
import "CJSONDeserializer.h"
import "JSON.h"
#synthesize homeTeam, awayTeam, awayTeam2;
(void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [NSURL URLWithString:#"http://yourserver.com/yourdata.json"]; // Modify this to match your url.
NSString *jsonreturn = [[NSString alloc] initWithContentsOfURL:url]; // Pulls the URL
//NSLog(jsonreturn);
// Look at the console and you can see what the restults are
NSData *jsonData = [jsonreturn dataUsingEncoding:NSUTF32BigEndianStringEncoding];
NSError *error = nil;
// In "real" code you should surround this with try and catch
NSDictionary * dict = [[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:&error];
if (dict)
{
rows = [dict objectForKey:#"users"];
[rows retain];
}
NSLog(#"Array: %#",rows); //making NOTE this NSLOG does print my JSON Data grabbed from the SQL Database
awayTeam2.text =[dict objectForKey:#"awayteam"];
awayTeam.text = [dict objectForKey:#"awayteam"];
[jsonreturn release];
CONSOLE: as you can see it grabs my JSON data just fine....
Array: (
{
awayicon = "Brampton.png";
awayteam = Mississauga;
homeicon = "Mississauga.jpg";
hometeam = Brampton;
hscfinal = 10;
id = 1;
}
)

Related

Display JSON as List in ViewController (Not in TableView)

I am producing a JSON string that I need to parse out and display onto the page. My JSON string outputs information about the contents of a CD like this:
[{"song_name":"Song 1","artist":"John","price":"$1"},
{"song_name":"Song 2","artist":"Anna","price":"$2"},
{"song_name":"Song 3","artist":"Ryan","price":"$3"}]
I would like to display the contents in my viewController in a list format displaying the song_name, artist, and price. I do not want to use a tableView to display this information, but would rather just have a list displayed. How might I go about doing this? I would assume that I need to use NSJSONSerialization, but have only used that for a tableView in the past. Thank you!
In addition to other answers, you can use only one label, just create NSMutableString (for dynamicly adding tracks info) with #"\n" between tracks info, pass it to label.text and set UILabel's property numberOfLines to 0
Follow these steps:
Parse the JSON and store the key-value pair(NSDictionary of CDs) in an NSArray (say infoArray)
Add a UIScrollview as a subview on your viewController's view.
Allocate UILabels dynamically, depending on infoArray count. Looking at your data I believe you can initialize labels with static frames i.e your y can remain static.
Add the text from the infoArray on this label.
Still, I would suggest use UITableView only. It is much simpler and a better approach
You make an array of dictionaries using NSJSONSerialization indeed, then you parse this array one by one and create a view of every dictionary. You're probably best of using a method for this:
-(UIView *) listView: (NSString *)songName andArtist:(NSString *)artist andPrice:(NSString *)price andIndex:(int)viewIndex {
//create your view here and do anything you want
UIView *subView = [[UIView alloc] init] autoRelease];
subView.frame = CGRectMake(0, viewIndex * 70, self.view.frame.width, 70);
//add labels and other stuff
// return the view
return subView;
}
The you add it to the current view by setting different Y values so they appear underneath each other by using the viewIndex of the former method... So if you have an array it goes something like this:
for (int i = 0; i < [array count]; i++) {
NSDictionary *dict = [array objectAtIndex:i];
NSString *songName = [dict valueForKey:#"song_name"];
NSString *artist = [dict valueForKey:#"artist"];
NSString *price = [dict valueForKey:#"price"];
UIView *tempView = [self listView:songName andArtist:artist andPrice:price andIndex:i];
[self.view addSubView:tempView];
}
You have to add it all to a scrollview otherwise you will run into the problem of to many rows on the page. Google for UIScrollView if you don't know how.
But I would recommend against this approach.. Tableviews are there with a reason. They are made for this stuff. Because the also provide for scrolling, drawing and refreshing. If you can, use them!

UILabel in different subviews

I'm creating my first app. It will be a catalog of products, that you can scroll through.
I created a UIScrollView with a width of 960 (320*3) and added a UIPageControl. Inside it I added 3 different view, each of them represents one of my products - with all the information I need - name, image, description, price, etc..
I can see the views move, and so I've set the first product with UILabel classes and UIImageView. I was wondering if it is possible to use NSArray and set the UILabel's text property and imageNamed in the next view as the user switches to it.
My problem is that each view has a different UILabel element.
Thanks for your help, it is much appreciated!
Yes you could use a NSArray to store the data for each of your views. I would suggest first creating a simple object with the properties labelText and imageName;
Then you can create a NSArray of your custom object like this:
MyObject obj1 = [MyObject new];
obj1.labelText = #"My Text 1";
obj1.imageName = #"My Image 1";
//Other objects..
then
NSArray *myArray = [[NSArray alloc] initWithObjects: obj1, obj2, obj3, nil];
Then When you switch pages simply do this:
MyObject *myPageInfo = [myArray objectAtIndex:pageNumber];
myLabel.text = myPageInfo.labelText;
mylabel.imageName = myPageInfo.imageName;
Hope that helps.

Loading 10k+ rows in iphone SQLite (FMDB)

I am creating a dictionary app and I am trying to load the terms into an iphone dictionary for use. The terms are defined from this table (SQLite):
id -> INTEGER autoincrement PK
termtext -> TEXT
langid -> INT
normalized -> TEXT
Normalized is used because I am writing in GREEK and I don't have icu on the sqlite engine for searching diacritics, so I am making a termtext diacritics/case insensitive. It is also the main search field, in contrast of termtext which could be the "view" field.
I have defined an class (like a POJO) like this:
terms.h
#import <Foundation/Foundation.h>
#interface Terms : NSObject {
NSUInteger termId; // id
NSString* termText; // termtext
NSUInteger langId; // langid
NSString* normalized; // normalized
}
#property (nonatomic, copy, readwrite) NSString* termText;
#property (nonatomic, copy, readwrite) NSString* normalized;
#property (assign, readwrite) NSUInteger termId;
#property (assign, readwrite) NSUInteger langId;
#end
terms.c
#import "Terms.h"
#implementation Term
#synthesize termId;
#synthesize termText;
#synthesize langId;
#synthesize normalized;
#end
Now in my code I use FMDB as the wrapper for the SQLite database. I load the terms using the following code:
[... fmdb defined database as object, opened ]
NSMutableArray *termResults = [[[NSMutableArray alloc] init] autorelease];
FMResultSet *s = [database executeSQL:#"SELECT id, termtext, langid, normalized FROM terms ORDER BY normalized ASC"];
while ([s next]) {
Term* term = [[Terms alloc] init];
term.termId = [s intForColumn:#"id"];
[... other definitions]
[termResults addObject:term];
[term release];
}
The whole termResults is then loaded to a UITableView (on viewdidload) but the loading takes up to 5 seconds every time I start my app. Is there any way to speedup that process? I have indexed id, termText and normalized on SQLite.
*** UPDATE: added cellForRowAtIndexPath ****
[.. standard cell definition...]
// Configure the cell
Term* termObj = [self.termResults objectAtIndex:indexPath.row];
cell.textLabel.text = termObj.termText;
return cell;
Since you seem to load the whole DB into memory anyway (and think it is a must) the whole point of using SQLite is almost gone.
So if the data is static (does not change), I would turn the DB into objects once, then serialize the objects (implement the NSCoding protocol) and store this array (or better yet, dictionary) using writeToFile:atomically:. Once you have that file (do that during development) you can easily load it at runtime with arrayWithContentsOfFile: which should be faster in this case.
Loading that much data into your app is going to take time. The best approach to take would be to load the data from the db on a separate thread to the main application thread. As each item is loaded, post a message back to the main thread to add an item to the array backing the table view. This way, your app load time will be short and your UI will be responsive whilst the data is loading from the db. Here's the basic idea:
NSMutableArray *termResults = [NSMutableArray array];
// Load each item from the db on a separate thread using a block
dispatch_queue_t globalQueue = dispatch_get_global_queue();
dispatch_async(globalQueue, ^() {
// Init the database
...
// Load the items from the db
FMResultSet *s = [database executeSQL:#"SELECT id, termtext, langid, normalized FROM terms ORDER BY normalized ASC"];
while ([s next]) {
Term* term = [Term new];
term.termId = [s intForColumn:#"id"];
// Add the loaded item to termResults on the main thread
// and refresh the table view
dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();
dispatch_async(mainDispatchQueue, ^() {
// Add the loaded item to termResults
[termResults addObject:term];
// Refresh the table view. This will only reload the visible items.
[tableView reloadData];
});
[term release];
}
});
Hope this helps.
Not a problem to read 10K records from sqlite into UITableView. First, I couldn't see reasons to do that. Second, you couldn't avoid time gap due to a lot of memory allocations. Memory allocation is a system call. And system calls are often slow. During load ios will send memory warnings to run apps resulting in longer gap. What will you do if you will need a million records? sqlite is used to avoid such memory data structures at all. If you see problems using unicode in sqlite on iphone (icu) - read here. I use this technic in several of my apps and all of them were approved to AppStore without problems.

trying to add dictionary objects to an NSMutableArray - afterward array returns null?

I just did a search for my particular question and although the answers are close, I can't get my head around the answer...so I need some assistance.
I'd like to populate an array (NSMutableArray I suppose) with a group of dictionary objects that are parsed from JSON strings...the dictionary part I got, the JSON parsing I got, but when I try to put these objects into the NSMutableArray and NSLog it I get (null)... here are my steps (in a general way)
edit 1:
-The array I am creating is called NewFinalArray. it is an NSMutableArray, declared at the .h file and synthesized (and now alloc'd and init'd) as noted in the viewDidLoad method of the DetailViewController. It's contents are to be displayed in a UITableView.
-In DetailViewController, I have been successful in creating a plain NSArray/NSMutableArray and populating it with values that display in my UITableView.
-In the new scenario, I am receiving the information to be displayed through JSON strings which are retrievable through dictionary objects. I am using the Stig JSON libraries for iPHone/iPad. I have no problems there.
-All I wanted to do is getting the existing dictionary objects (which I can loop through from the existing array and see) and add them to a new Array to be used for displaying menu items in my UITableview.
I declared my mutableArray in my .h file
#interface blah : ...,...,...{
NSMutableArray *newFinalArray;
// other vars and IBOutlets
}
#property (nonatomic, retain) NSMutableArray *newFinalArray;
// other #property and (IBAction) stuff
#end
I then synthesize it in my .m file... I even alloc/inited it at viewDidLoad (it's a DetailViewController)
#synthesize this,that, newFinalArray; // keep track of newFinalArray, that's the one I want
- (void)viewDidLoad {
// other code
[[newFinalArray alloc] init]; // ya returns a warning, about not responding to alloc, but whatever (for now)
// I also tested of course without having to do that.
in my method that uses newFinalArray, the method is a recursive function that calls itself. each time it calls, it should add the dictionary object to the array (or does it?)
-(void)digTree:(NSArray *)array{
for (NSDictionary *dictionary in array){
// looping through the array
[self newFinalArray addObject:[dictionary]];
// more other code, and somewhere along the way I recurse
[self digTree:anotherArray];
}
}
when I try to NSLog (#"my final array is %#", newFinalArray) I get (null).
I am probably missing something here. I tried to add "nil" at the end. I am a little new/green to this , so if someone can lend a hand and let me know how to populate my newFinalArray with these dictionary objects it would be most appreciated.
[[newFinalArray alloc] init];
should be:
newFinalArray = [[NSMutableArray alloc] init];
This line is wrong too:
[self newFinalArray addObject:[dictionary]];
it should be:
[newFinalArray addObject:dictionary];
The first thing I notice that is wrong, is it should be:
newFinalArray = [[NSMutableArray alloc] init];
in viewDidLoad. See if that fixes it. It looks like there are other things wrong as well, so turn on warnings and see what else the compiler warns you about for hints.
How are the dictionaries stored? An alternative/probably easier way to do this would probably be to use arrayWithObjects:. Also, when using addObject:, there is no need to add nil (in fact, you can't add nil).

Filling an NSMutableArray with a Set of Classes and Then Getting them Back

Hopefully I can make this clear, but I am new to Objective-C and to be honest not great with Arrays in the first place.
So, I have a Singleton class (called SingletonState) that I am using to pass variables around my app (please can we leave the whether I should use Singleton classes out of this - I will fix that later). In this class, I have an NSMutableArray (called arrayMyEvents). I have also created a class that I am going to store a list of events (called EventClass). When the user logs in, I call a web service and get back 3 strings. The 3rd string is a comma separated list of value. I parse the data and populate the custom class EventClass. I then add this class to the SingletonState.arrayMyEvents.
I have all of this working. I can go to another ViewController and access the "count" of items in arrayMyEvents.
PROBLEM: I now want to edit one of the ScheduledEventsClass"es" in my array. How do I get access to it and edit some of the properties and update the one in my SingletonState class?
Here is some of the code, that I've tried:
NSString *sWebServiceEvents = [[NSString alloc] initWithFormat:#"%#", [result objectAtIndex:2]];
if ( [ sWebServiceEvents isEqualToString:#"NULL" ] != true ) {
NSArray *arrayEvents = [sWebServiceEvents componentsSeparatedByString:#","];
// If the array has not been initialized they initialize it.
if (sharedState.arrayMyEvents == nil) {
sharedState.arrayMyEvents = [[NSMutableArray alloc ] init ];
}
for (NSString * sEvent in arrayEvents) {
// Set equal to the value of the array (the Event Number) at the same
// position as the row that we are being asked to return a cell/row for.
EventClass *eventClass = [[EventClass alloc] retain];
eventClass.sEvent = sEvent;
[ sharedState.arrayEvents addObject:eventClass ];
}
NSLog(#"LoginView - sharedState.arrayMyEvents Count: %d", [sharedState.arrayMyEvents count]);
}
Here is me trying to access it in another ViewController:
EventClass *eventClass =
[sharedState.arrayMyEvents objectAtIndex:row ];
NSLog(#"eventClass.sEventNumber: ", eventClass.sEventNumber);
eventClass.sLocation = #"Jason's Big Location";
You're going to have some memory leaks from the sEvent loop. [[EventClass alloc]retain] leaves you an uninitialized EventClass object with a reference count of 2. You'll need to change that to [[[EventClass alloc] init] autorelease] to keep it from leaking. The arrayEvents NSMutableArray will retain it during the addObject: call. (Shouldn't that be [sharedState.arrayMyEvents addObject: eventClass] in the loop?)
After that, all you have to do to edit the EventClass object in the second block of code is edit it. The eventClass variable is a pointer to an object in the array. Anything done to that object doesn't affect the pointer referencing it, it affects data referenced by it. The code you have in the second block should change the sLocation of the selected object as you intend.
You have a few more memory leaks in there, too. Use Cmd-Shift-A to build with the static analyzer and it'll tell you where.
Maybe the problem is that you put them in sharedState.arrayEvents but try to take them out of sharedState.arrayMyEvents. Different variables.
Also, lots of memory leaks.
Thanks John and St3fan, your answers and time are appreciated!!!
I think that I figured out my issue:
Basically, the class that I created (EventClass) had the properties setup like this:
#property (nonatomic, assign) NSString *sStudyNumber;
#property (nonatomic, assign) NSString *sTheater;
but, they should be (or at least I got it to work like this):
#property (nonatomic, retain) NSString *sStudyNumber;
#property (nonatomic, retain) NSString *sTheater;
Then, in my second view I was able to do this:
EventClass *eventClass = [sharedState.arrayMyEvents objectAtIndex:row ];
NSLog(#"MyEvents: %#", eventClass.sEventNumber);
eventClass.sLocation = #"Jason's Big Location";
I then checked it in another method of the view using this and it was still there:
EventClass *eventClass = [sharedState.arrayMyEvents objectAtIndex:row ];
NSLog(#"MyEvents: %#", eventClass.sEventNumber);
NSLog(#"MyEvents: %#", eventClass.sLocation);
I also, checked it in yet another view and the value was maintained in the SharedState.arrayMyEvents without issue. :)
In the end, I believe that I boiled down to the difference between "assign" and "retain".
Now, on to the memory leaks :(
Please, let me know if you see any other issues with this.
Thanks,
Jason