iPhone networking game - iphone

I already know how to make a online game using wi-Fi and bluetooth, but now i'm trying to implement a simple game over the internet(like a tic-tac-toe), but i'm kind lost.
I tried GET/POST, but i have no idea in how to notify a player that's waiting to move, and how to preserve the game state.
Do i have to open a socket on the server side, and connect from within the app?
I already made a extensive search, but i can only find about bluetooth and wifi, and that's not what i need.
Thanks everybody!

I would recommend this library: http://code.google.com/p/cocoaasyncsocket/
For the server side, you could use something like node.js or Python Twisted to open socket connections.
Sample code from one of my own projects. This sets up a socket that just reads from the host every 10 seconds. Your game will be a little different:
- (void) createSocket {
aisSocket = [[AsyncSocket alloc]initWithDelegate:self];
NSError *error;
[aisSocket connectToHost:myServerString
onPort:myServerPort
error:&error];
}
- (BOOL)onSocketWillConnect:(AsyncSocket *)sock {
NSLog(#"socket will connect");
return YES;
}
- (void) readData:(NSNotification*)note {
[[note.userInfo objectForKey:#"sock"] readDataWithTimeout:100 tag:0];
}
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port {
NSLog(#"The socket is connected: %d", [aisSocket isConnected]);
NSDictionary *dict = [NSDictionary dictionaryWithObject:sock forKey:#"sock"];
NSTimer *timer = [[NSTimer scheduledTimerWithTimeInterval:(10)
target:self
selector:#selector(readData:)
userInfo:dict
repeats:YES]retain];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}

Go read Apple's WiTap Sample code, it should match what you are trying to do.
Also consult GameKit Programming Guide to know how to make multiple devices discover themselves then communicate with each other in a game (or anything else)

Related

Why is this CMDeviceMotionHandler never called by CoreMotion?

I've included the CoreMotion framework in my project and imported the CoreMotion framework in the header of my view controller:
#import <CoreMotion/CoreMotion.h>
Then in -viewDidLoad I have this simple test code which I run on an iPhone 4 with iOS 4.3:
- (void)viewDidLoad {
[super viewDidLoad];
CMMotionManager *motionManager = [[CMMotionManager alloc] init];
[motionManager setDeviceMotionUpdateInterval:0.1];
CMDeviceMotionHandler motionHandler = ^(CMDeviceMotion *motion, NSError *error) {
NSLog(#"foo");
};
[motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:motionHandler];
NSLog(#"merde!");
}
When I run the project on the device and move it around, I never get a "foo" log. Also, I tried setting a breakpoint in the motion handler block and it never halts there. But I do get the "merde!" log, so this code is definitely executed.
Why is core motion not calling my handler? My iPhone 4 is functional. Accelerometers and gyro work perfectly in other apps. There is no hardware bug.
I had very similar code running successfully, same applies to the available samples in the Event Handling Guide for iOS (there is only an appropriate one for gyro data). But there is one major difference:
All implementations hold their own reference to the opereation queue with operationQueue = [[NSOperationQueue currentQueue] retain]; or build their own. So hopefully this helps to get more than 'merde' in your logs ;-)

how to apply the backgroud process in my iPad application without effecting the process running on foreground?

I'm Developing an iPad application where I need to download file from the Webservice and I don't want it affect any other process running on the foreground.
I am displaying the data from the local database in my app and also this data is coming from the web service.
Help Is Appreciated.
Thank You Very Much in advance.
NSURLConnection and its delegate method will allow an asynchronous(background thread) load of a URL request.
Refer the NSURLConnection Class Reference
After getting the data from the server you should parse it on another secondary thread. Then you can save it to the Database.
You can find a better demonstration in the Apple sample apps. Please check the TopPaid app .
This sample app don't have a Database management module. But will teach you to develop a Universal (iPad and iPhone compatible app).
Few thoughts:
you can run the download process on separate thread.
Write a class as below
#interface FileDownloader : NSOperation
//with following methods:
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:
[NSURLRequest requestWithURL:
[NSURL URLWithString:fileRecord.fileURLString]] delegate:self startImmediately:YES];
you can use thread use below method to detach thread
[NSThread detachNewThreadSelector:#selector(yourMethod) toTarget:self withObject:nil];
now perform your task in method
-(void) yourMethod {
//ur work
}
good luck
When downloading from a service in the background, I prefer to use synchronous calls running on a separate thread. This is how I do it in most of my apps.
call my generic method that spins a new thread
[[MyServiceSingleton sharedInstance] doSomeWorkInBackground:param1];
within singleton - define private method - doSomeWorkBackgroundJob (I use the empty category approach) to call within doSomeWorkInBackground method
[self performSelectorInBackground:#selector(doSomeWorkBackgroundJob:) withObject:param1];
within background job - create pool, do work, drain pool
- (void)doSomeWorkBackgroundJob:(NSString *)param1 {
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
assert(pool != nil);
// you can call another method here or just create your synchronous request and handle the response data
[pool drain];
}

GKSession - what if I have Bluetooth and Wi-Fi turned off?

I'm working on an iPhone app that will allow for peer-to-peer connections. From what I understand, I have the choice between using GKPeerPicker or the GKSession. I don't like the idea of using the PeerPicker because I want to show a custom interface, so I decided to go with GKSession, and hey, BONUS is that it also works over Wi-Fi, whereas the Peer Picker does not.
OK, so problem is... what if the user has both Bluetooth and Wi-Fi turned off? In the Peer Picker, there is a prompt to turn Bluetooth on w/o leaving the app. GKSession doesn't have it... but woah wait a second, it appears that I can't even check to see if Bluetooth is on or not programatically!
Carpe Cocoa claims no problem, just use the Delegate's session:didFailWithError: method. But, as it explains in the comments... that doesn't seem to work anymore! And in my experience, I concur.
Is there some other way to programmatically check if Bluetooth is on? Is this something that I should be leveraging Reachability for? Or is it just a bug that Apple has yet to fix?
To be more specific, I'm creating my session like this:
GKSession *aSession = [[GKSession alloc] initWithSessionID:nil
displayName:user.displayName
sessionMode:GKSessionModePeer];
self.gkSession = aSession;
[aSession release];
self.gkSession.delegate = self;
self.gkSession.available = YES;
[self.gkSession setDataReceiveHandler:self withContext:NULL];
The class implements the GKSessionDelegate, and I know that it's working because when I have bluetooth turned on, the delegate methods are called no problem. I've implemented them as such:
#pragma mark -
#pragma mark GKSessionDelegate methods
- (void)session:(GKSession *)session peer:(NSString *)peerID didChangeState:(GKPeerConnectionState)state {
if (GKPeerStateAvailable == state) {
[session connectToPeer:peerID withTimeout:10];
} else if (GKPeerStateConnected == state) {
// gets user
NSError *error = nil;
[session sendData:user.connectionData
toPeers:[NSArray arrayWithObjects:peerID,nil]
withDataMode:GKSendDataReliable error:&error];
if (error)
NSLog(#"%#",error);
}
}
- (void)session:(GKSession *)session didReceiveConnectionRequestFromPeer:(NSString *)peerID {
NSError *error = nil;
[session acceptConnectionFromPeer:peerID error:&error];
if (error)
NSLog(#"%#",error);
}
- (void)session:(GKSession *)session connectionWithPeerFailed:(NSString *)peerID withError:(NSError *)error {
NSLog(#"%#",error);
}
- (void)session:(GKSession *)session didFailWithError:(NSError *)error {
NSLog(#"%#",error);
}
None of the log statements are printed and I set breakpoints in each method, but none of them are hit when the user has both Bluetooth and Wi-Fi turned off. I was hoping that something would happen to trigger session:didFailWithError: so that I could prompt the user to turn on Bluetooth or connect to a Wi-Fi network.
Now in iOS 5, this can be achieved like so:
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:FALSE], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
NSMutableArray * discoveredPeripherals = [NSMutableArray new];
CBCentralManager * manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
[manager scanForPeripheralsWithServices:discoveredPeripherals options:options];
[manager stopScan];
This requires that you import the CoreBluetooth framework in iOS 5. If bluetooth is off, the system will pop up an alert view which will offer the choice to turn bluetooth on. Otherwise, if it finds a peripheral it will call a corresponding delegate method, but if there is nothing in that implementation you don't need to worry about it.
I agree with Martin Gordon, but a workaround might be to use Apple's reachability.
Interesting point, have you tried testing it with Bluetooth OFF and the WiFi ON? I found out recently that although my program was calling this 'Bluetooth Unavailable' message, it wasn't in fact using Bluetooth AT ALL but was connecting over my WiFi network. I don't know of a way to force GKSession into a Bluetooth connection without using Apple's PeerPicker object, but the PeerPicker object does allow for people to make their own interfaces. What it doesn't seem to allow is connection types other than Peer, so if you want a Client/Server arrangement it's not going to be much help.
-Ash
You can switch on Blutooth programmatically, by using Apple's private API (i think BluetoothManger.h), but be careful , it will cause rejection in the Apple App Store push.
I second the notion of using Apple's reachability. As a bonus it's listed as one of the Apple App Store submission guidelines.
It's not that hard to implement either as much of the code needed is already written for you.
Slf provided a link to some source code using the Reachability class, additionally here's a link to Apple Dev's official reachability example.
However, make sure you are checking for connectability asynchronously.
I'm using it in my app and although it isn't the best solution at least it notifies the user that he/she needs to adjust the connection settings or that no networks exist.
You should use the same sessionID.

Getting list of bluetooth devices nearby on iphone sdk

I need to be able to search for all bluetooth devices nearby and just get there ids. I don't need to pair at all. I am using iphone 2.3 beta.
Is this possible l have tried using GameKit and no luck does anyone know how to do this.
BOOL result = NO;
if (!session) {
session = [[GKSession alloc] initWithSessionID:#"SCANNER"
displayName:nil
sessionMode:GKSessionModePeer];
self.session.delegate = self;
[self.session setDataReceiveHandler:self withContext:nil];
self.session.available = YES;
result = YES;
}
it dies on [self.session setDataReceiveHandler:self withContext:nil];
with the following error
Scanner[42754:207] Error: 30500 -- Invalid parameter for -setDataReceiveHandler:withContext:.
then
~ DNSServiceRegister callback: Ref=471fa40, Flags=2, ErrorType=0 name=00rusor1A..iPhone Simulator regtype=_q1eu29voete9jf._udp. domain=local.
Does self implement the required method
- (void) receiveData:(NSData *)data fromPeer:(NSString *)peer inSession: (GKSession *)session context:(void *)context;
somewhere? Otherwise, it is unable to satisfy the needs of the -setDataReceiveHandler:withContext: method. Also, I don't believe you can access Bluetooth functions from within the iPhone Simulator.
Overall, I don't think this will do what you want. GameKit uses Bonjour discovery to detect other iPhones / iPod touches running similar game sessions within a local Bluetooth network. It will not detect all Bluetooth devices in the vicinity. You can use lower-level Bonjour discovery yourself to find all Bonjour devices that are network-accessible via WiFi or Bluetooth, but Bluetooth access itself is abstracted away from you.

Needing a design pattern/example link for iPhone network connections

I'm sorry if this is a basic question. I've been googling, searching StackOverflow, and looking through example code for hours and haven't found anything satisfactory for my skill level.
I'm wanting something like a design pattern for handling network functions on the iPhone SDK. I have heard of people using a singleton class but have heard there are better ways for asynchronous connections. Would NSOperation be useful? I am fairly new to object oriented programming but am needing to make occasional calls to my webserver through HTTP for my current app and hope to find a solution that is easily reusable.
I've looked through the NSURLConnection docs and can get the basic functionality but the programming structure is messy and I'm not sure how to better organize it. Is there sample code for this that separates out these functions into their own class? A link to an example that does this would be greatly appreciated!
thanks!
I've been dealing with this same question for a while now...
If you're effectively doing a GET on a simple resource, and you're confident that the resource will always be there & accessible, there's an easy way to do it:
NSURL *URL=[[NSURL alloc] initWithString:#"http://www.google.com/"l];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
//TODO This needs to have timeouts & such set up, maybe parallelism
NSString *results = [[NSString alloc] initWithContentsOfURL :URL];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
That's a REALLY simple way to do it, but as my comment says, not very robust or reliable.
A slightly more robust, yet still reasonably simple, is replacing the NSString line with:
results = [[NSString alloc] initWithContentsOfURL:URL encoding:NSASCIIStringEncoding error:&err]; // possibly NSUnicodeStringEncoding
if (err!=nil) NSLog(#"Error occurred: %#", [err localizedDescription]);
That will at least TELL you if there's an error...
ASIHTTPRequest provides a lot of neat & useful network functionality for dealing with resources over the internet. http://allseeing-i.com/ASIHTTPRequest/ - the developer has been VERY responsive on his Google Group. I really wanted to use that, and may get back to it when/if it supports SSL Client Certificate authentication (which is what my project requires).
NSURLConnection, as described above - that's what I'm using now in my project. I would imagine that this will satisfy almost all needs, but it's (in my opinion) more tricky to use. And to be honest, I'm still having a little trouble wrapping my mind around how to integrate asynchronous data loading into my application. But if it will work for you - and it probably will, Apple is using it all over the OS and its apps - that's your best bet!
One possible approach is to use the NSURLConnection (as you mentioned).
Inside your .h file:
NSMutableData *connectionData;
Also add a property for connectionData...
Inside your .m file:
- (void)updateFromServer {
// You might want to display a loading indication here...
NSMutableData *connectionDataTemp = [[NSMutableData alloc] init];
self.connectionData = connectionDataTemp;
[connectionDataTemp release];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL: your_url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection release];
[request release];
}
#pragma mark -
#pragma mark NSURLConnectionDelegate
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Add the received bulk of data to your mutable data object
[self.connectionData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// Use your data
// If there is a loading indication displayed then this is a good place to hide it...
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// Handle error
// If there is a loading indication displayed then this is a good place to hide it...
}