Creating a highscore like system, iPhone side - iphone

I'm sorry for opening a new question, I had to - as I wrote the other question from my iPhone as unregistered user and it is not very comfortable to write from the iPhone.
Rephrasing the question:
Is it possible to use the:
[NSMutableArray writeToURL:(NSString *)path atomically:(BOOL)AuxSomething];
In order to send a file (NSMutableArray) XML file to a url, and update the url to contain that file?
for example:
I have an array and I want to upload it to a specific URL and the next time the app launches I want to download that array.
NSMutableArray *arrayToWrite = [[NSMutableArray alloc] initWithObjects:#"One",#"Two",nil];
[arrayToWrite writeToURL:
[NSURL urlWithString:#"mywebsite.atwebpages.com/myArray.plist"] atomically:YES];
And at runtime:
NSMutableArray *arrayToRead =
[[NSMutableArray alloc] initWithContentsOfURL:[NSURL urlWithString:#"mywebsite.atwebpages.com/myArray.plist"]];
Meaning, I want to write an NSMutableArray to a URL, which is on a web hosting service (e.g. batcave.net), the URL receives the information and updates server sided files accordingly.
A highscore like setup, user sends his scores, the server updates it's files, other users download the highscores at runtime.
I hope this is clarified.
Edit: What I am looking for is scripting PHP or ASP so the website, the URL where the data is sent to would know how to handle it. I want an example or a tutorial on how to implement this scripting for handling data, if it's possible to do this on a web hosting service.
~Thanks in advance.

To answer the question "How do I create a high score like system?", there are multiple parts of the system:
You need an ID for each user (a GUID generated on the iPhone, together with the users name should be sufficient).
You need a server that: remembers high scores; receives high scores from users; either displays (on a web site) the high scores and/or makes the high scores available for download to the phone.
You need some fraud protection, although that is likely fighting a losing battle against jailbreakers.
On the iPhone app side, you might want to be able to download the current high scores for display, which is done easily enough with something like:
int statusCode = 0;
NSData* result = nil;
NSHTTPURLResponse* response = nil;
NSError* error = nil;
NSString* url = #"http://www.yourserver.com/highscores.php"; // returns XML plist data
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:180];
result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
// NSLog( #"NSURLConnection result %d %# %#", [response statusCode], [request description], [error description] );
statusCode = [response statusCode];
if ( (statusCode == 0) || (!result && statusCode == 200) ) {
statusCode = 500;
}
Since it is synchronous, you might want to put it inside an NSOperation. Alternatively, you can use
+ (NSURLConnection *)connectionWithRequest:(NSURLRequest *)request delegate:(id)delegate
To send high score data, because it is so small, the easiest way is simply to encode it in the URL.
NSString* url = [NSString stringWithFormat:#"http://www.yourserver.com/sethighscores.php?uid=%#;name=%#;score=%d;antifraud=%#", [uid encodeParameter], [name encodeParameter], score, [secureHash encodeParameter]];
Where encodeParameter is a custom category on NSString that encodes URL parameters and secureHash is a string representing a one way secure hashing of the uid, name, score and some secret known to your iPhone app and your web site. You'll need to figure these out on your own or ask separate questions since this is already getting long.

According to NSData writeToURL docs (at least for iPhone OS 2.2.1):
"Since at present only file:// URLs are supported, there is no difference between this method and writeToFile:atomically:, except for the type of the first argument."
Although the docs for NSArray/NSDictionary/NSString do not specifically mention the restriction, it would seem highly likely that the same restriction applies.
So you will have to upload the XML using some other mechanism.
Also, web sites generally are read only, unless you provide specific code on the web server to support uploading.

Related

How to store NSData from NSURLConnection sendSynchronousRequest as a pdf file to documents directory in iOS?

I am getting the NSData using
NSData * responseData = [NSURLConnection sendSynchronousRequest:mutableUrlRequest returningResponse:nil error:nil];
How to store this as a PDF to local documents directory? My service is in java which returns byte array.
Thanks !
try like this
NSString *docPath=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
[data writeToFile:[docPath stringByAppendingPathComponent:#"name.pdf"]
atomically:YES];
You really need to confirm that your request has been successful:
Provide a pointer for the response which on return contains the status code and the MIME type of the response data, possibly also content length and other useful info. Check against what you expect.
Provide a NSError pointer, too in order to get the error when the connection fails (returns nil).
That's what you should always do when you make a toy app. When you make a more serious app, you should use the asynchronous style to perform a network request. Basically, you implement the two NSURLConnection Delegate protocols. There is lot of info already in SO how to accomplish this, and as well in Apple samples. If you have any specific questions, please ask again :)
How to store this as a PDF to local documents directory?
This question has been answered already.

Objective-C: Parsing a non-xml website

I'd like to develop a very simple "bus timetable" app that loads a particular URL and can use the HTML to figure out bus numbers, their routes and expected times. Unfortunately it's a very simple website, so the data is spread across TD and DIV fields, rather than in xml.
Can anyone provide some pointers on where to start? I've had a look at NSURL, NSURLConnection and the like, and am able to download the contents of an HTML file, but I'm unsure what to do next.
Many thanks.
There are many ways to accomplish this task. Ultimately, you will want to retrieve something an easily-processed format other than raw html. Here is one way to do it:
I would recommend writing a server-side script that converts the html into an easily-digestible format, such as JSON.
If you have php experience, you write a script / web-service that grabs the needed elements and place the content in an associative array. Place the script on your server and have your application call the web-service URL when ready to retrieve the info.
Finally, return the information as a JSON object and parse the JSON into your app.
<?php
//parse html into the $array variable.
$array = json_encode($array);
echo $array;
?>
I would recommend using the SBJSON library for parsing the JSON object: Take a look at SBJSON
Initiate your NSURL request by calling the script URL.
NSURLRequest *request =[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.yoursite/script.php"]];
If the request is successful, parse the resulting JSON: (assuming use of SBJSON library)
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData: responseData encoding: NSUTF8StringEncoding];
[responseData release];
NSError *error;
SBJSON *json = [[[SBJSON alloc] init]autorelease];
NSDictionary *busData = [json objectWithString:responseString error: &error];
//busData contains bus data that you formatted...
Beware, this is assuming that you want to add your data to a dictionary and then display it appropriately. I consider this a mere snippet for formatting data in a way you desire. Parsing all of the html within the app may difficult and that is why I advocate formatting the data as JSON first. If you decide to go the XML route, there are several XML parsers as well.

How to keep a connection alive using ASIHTTP? I need to make multiple requests, but can't afford to open, then close a request connection

I have a method that I call to make web service requests using GET. It looks like this:
- (UIImage*)getImageWithSeriesGUID:(NSString*)seriesGUID ImageID:(int)imageID {
NSString * unescapedString = RIVERWOODS_GET_IMAGE(seriesGUID, imageID);
NSURL *url = [[NSURL alloc] initWithString:[unescapedString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setRequestMethod:#"GET"];
[request addRequestHeader:#"Connection" value:#"Keep-Alive"];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
NSData *response = [request responseData];
//NSLog(#"Size: %#",[response length]);
NSString *content = [[[NSString alloc] initWithData:response
encoding:NSUTF8StringEncoding] autorelease];
NSLog(#"Data: %#", content);
UIImage *image = [UIImage imageWithData:response];
return image;
}
return nil;
}
This approach works ok, but it is just REALLY slowly. On the other end I am iterating through a for loop so this method gets called 20 times if the picture array I need to collect has 20 images. I am looking to improve the efficiency of this process, and I am thinking that I should be able to iterate through all the image Id's I need to collect right here in this method.
It seems to me that the reason this goes so slowly is because the multiple requests that we keep opening and closing. THe images I am pulling in are on average ~15kb.
My question: What can I do to change this method around to make it so I can improve efficiency and take advantage of the HTTP keep-alive features? I am thinking that instead of passing in an image ID, I can just pass in the count of the array I need to make, and then setup a for-loop of some sorts here in the request method which would then allow me to pass back an array of images...
Is that the way to go? Is there something I am missing? I appreciate your help and input!!
The reason why this is slow as hell is that you're doing the requests synchronously (which is always a no-no anyway), one-by-one. You need to refactor your download method to work asynchronously, and concurrently.
My approach to requesting data on the wire in that manner is as follows:
Create a global network connection 'controller' (accessible from your App Delegate), which can create an ASINetworkQueue on the fly when required and release it when no requests remain
Wrap your requests into a subclass of ASIHTTPRequest, and override the done/fail methods in those subclasses (make them fire a notification with returned data if you like; or write to disk and update a db with their reference).
For every request, grab the queue reference, and add your request to the queue.
The queue will grow and shrink as needed
If I were at my computer I'd check into github an example of this, but really the only difficult part is the global connection manager, and the ASI* guys have written a great example here on gist.github. Also, a better explanation of the above (where I learnt it from) is here.

problems with iphone code to check server file date

I want to check the dates on files -- zip, jpg, or whatever -- on my server and, if they are newer than the copies on my iPhone, to download them.
I wrote the following method based on a post here that's about a year old. It has two problems:
+ (NSString *) f_GetServerFileDate:(NSString *)MyURL {
NSURL *oURL = [NSURL URLWithString:MyURL];
NSURLRequest *oRequest = [NSURLRequest requestWithURL:oURL];
NSHTTPURLResponse *oResponse;
[NSURLConnection sendSynchronousRequest:oRequest returningResponse:&oResponse error:nil];
if ( [oResponse respondsToSelector:#selector( allHeaderFields )] ) {
NSDictionary *metaData = [oResponse allHeaderFields];
return [metaData objectForKey:#"Last-Modified"];
} else {
return #"00000000";
}
}
Problem 1: It returns "00000000" when given "http://www.mysite.com/myzip.zip" as a URL.
Problem 2: For an Active Server Page (just a test; not that I'd really download one) it returns a date that has no bearing on the date the file was last uploaded or modified.
What's the right way?
This is probably less a problem of your iPhone code but rather of the web server. A web server is not required to include the Last-Modified header attribute. And for dynamic pages (such as ASP pages) it is correct to return the date when the page was dynamically generated (i.e. the current date) and not the date when the page was developed or deployed.
I suggest you use a browser extension such as Live HTTP headers for Fireofx to observe what HTTP header attributes the web server returns. If the date is missing, you'll be out of luck (unless you have access to the web server and can fix it there).
Furthermore, your code will always download the image no matter when it has been last modified. You can prevent this if you include the HTTP header If-Modified-Since in your request. That way the web server will send the image if it has been modified since the specified date or just send a 304 (Not modified) result code if the image is still up to date. But again: It depends on the web server if this option is supported and it only works for static content unless the author of the web application has specifically implemented it.

How to uniquely identify nsmangedobject with string?

I'm using Core data and region monitoring. The only way to distinguish between monitored regions is with a NSString for identifier. I'd love to use NSManagedObjectID, but I can't get it to work.
What I've tried:
NSURL *objURL = [managedObjectID URIRepresentation];
NSError *err;
NSString *identifier = [NSString stringWithContentsOfURL:myURL
encoding:NSASCIIStringEncoding
error:&err];
the error I get is:
The operation couldn’t be completed. (Cocoa error 256.)
Any ideas of a better way? Or what I'm doing wrong?
You should not get the contents of the URI of the NSManagedObjectID. stringWithContentsOfURL:encoding:error: tries to load the resource pointed by the URI; it uses appropriate operations depending whether the URI is http or file or etc. But it doesn't know how to deal with an NSManagedObjectID URI, and it's not what you want to do anyway.
Instead, I guess what you want to do is
NSString*identifier=[objURL absoluteString];
This gives a string representation of the URL.
I'll add Marcus's comment so that everyone will notice:
Be aware that the objectID can and does change, especially when a migration occurs. Do not rely on that value to be consistent between one launch of the application and the next.