Game Center Host - iphone

I am currently creating a Game Center game, and am using the peer-to-peer functionality available. However, I would like to select one of the players (2 players) to act as a host, to ensure synchronization.
What is the best way to select a host (even randomly) from the players available and ensure that the other device knows which host was chosen?

This is a nice, simple tutorial with code that demonstrates how to do this. They randomly choose one of the peers to be the host. Hope that Helps!

already posted answer , still here is sample code to do that thing
NSString *uid = [[UIDevice currentDevice] uniqueIdentifier];
CoinTossID = [uid hash];
now in delegate Function
- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID
{
NSMutableArray *ReceivedArray = [[NSMutableArray alloc] init];
ReceivedArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];
int flag = [[ReceivedArray objectAtIndex:0] intValue];
[ReceivedArray removeObjectAtIndex:0];
int CoinValue = [ReceivedCoinTossID intValue];
if(CoinValue > CoinTossID)
{
isPlayer1 = YES;
}
else
{
isPlayer1 = NO;
}
}

Related

UIApplication -scheduleLocalNotification: very slow when called by UIApplication -appWillTerminate:

I set the "application does not run in background" in my info.plist, so when user tap home button, app quits.
When my [UIApplication -appWillTerminate:] called, I will schedule 64 local notifications to system, all of them are non-repeating.
but that take a seemingly long time(6.17 seconds) on a iPhone4 with iOS6.0.1.
When I look at the time profiler, I found that the curve is very strange, it don't take much CPU time, but it do take a lot of time.
Also when I look at the call tree, 93% of the time is spent on [UIApplication -scheduleLocalNotification:] in the time range showed in the image.
Why?
This is how I generate my notifications:
UILocalNotification *n = [[[UILocalNotification] alloc] init] autorelease];
n.alertBody = #"some body";
n.hasAction = YES;
n.alertAction = #"some action";
n.fireDate = #"some date";
n.repeatInterval = 0;
n.soundName = #"my sound"
n.userInfo = aDictionaryWithAStringAbount10CharacterLongAnd2NSNumber.
[self.notifications addObject:n];
This is how I schedule my notifications:
-(void)endProxyAndWriteToSystemLocalNotification
{
_proxying = NO;
NSDate *dateAnchor = [NSDate date];
NSEnumerator *enumerator = [self.notifications objectEnumerator];
NSInteger i = 0;
while (i < maxLocalNotifCount) {
UILocalNotification *n = [enumerator nextObject];
if (!d) {
break;
}
if ([n.fireDate timeIntervalSinceDate:dateAnchor] >= 0) {
[[UIApplication sharedApplication] scheduleLocalNotification:n];
i++;
}
}
[self.notificationDatas removeAllObjects];
}
This would help:
-(void)endProxyAndWriteToSystemLocalNotification {
[[UIApplication sharedApplication] setScheduledLocalNotifications:self.notifications];
}
iOS 4.2 and later
read UIApplication Class Reference for detailed description
I think the problem is that you are trying to schedule 64 local notifications. Is there a reason to do all of these on app termination? Apples scheduleLocalNotification was not designed to be called so many times on termination

Iphone: unable to show photos using AlAssetsLibrary

I currently sending ipa to friends for testing. Funny thing is, one of my tester able view her photos stored on her phone which was running IOS 5 using iPhone 4.
Another 2 testers: one has iPhone 4 (IOS 4.3.3) , and iPhone 3GS (IOS 5.0.1) both of them can't see photos stored on their phone.
These are the code I have used:
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
void (^assetEnumerator)(ALAsset *, NSUInteger, BOOL *) = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
if(result != NULL) {
//NSLog(#"See Asset: %#", #"ggg");
[assets addObject:result];
}
};
NSLog(#"location = %i length = %i ", range->location, range->length );
void (^assetGroupEnumerator)(ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop) {
if(group != nil) {
NSRange *datarange = malloc(sizeof(NSRange));
range->total = [group numberOfAssets];
datarange->location = [group numberOfAssets] - range->location - range->length;
datarange->length = range->length;
NSLog(#" total = %i", range->total);
int location = [group numberOfAssets] - range->location - range->length;
if (location < 0)
{
datarange->location = 0;
datarange->length = [group numberOfAssets] - range->location;
}
NSIndexSet *indexset = [ [NSIndexSet alloc] initWithIndexesInRange:*datarange];
[group enumerateAssetsAtIndexes:indexset options:NULL
usingBlock:assetEnumerator];
[indexset release];
free(datarange);
[self loadAssetToScrollView:assets];
}
};
[assets release];
assets = [[NSMutableArray alloc] init];
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
usingBlock:assetGroupEnumerator
failureBlock: ^(NSError *error) {
NSLog(#"Failure");
}];
[library release];
I saw somebody say about asynchronous thing in some other threads but don't know is it the case. He say put dispatch_async in the enumerate group block.
Does anyone know what is wrong.
Additionally, one of tester with iOS 4.3.3 can show his photos after enabling location services under General->Setting. Why we have to enable it? Can we enabled it on code since it will be quite disturbing to the user who using our application.
Also on iOS 5.x you must retain your ALAssetsLibrary instance so long as you need to work with the collected assets. When you release your ALAssetsLibrary instance like in your code just after calling [library enumerateGroupsWithTypes:…] all the collected assets will be invalid.
See also the ALAssetsLibrary doc - overview:
"… The lifetimes of objects you get back from a library instance are tied to the lifetime of the library instance. …"
Yes, it is incredibly frustrating, but that is how it is, and you cannot enable location services in code (that is a good thing though).
I would move the first block ^assetGroupEnumerator to the heap by [[<#block#> copy] autorelease]. Why? Because this block would be autoreleased by the runloop, if there are many assets need to be enumerated through.
One more thing: don't use [self loadAssetToScrollView:assets]; inside the block but get the weak reference of self before the block like this:
__block YourExampleClassInstance *weakSelf = self;
and further use this weakSelf instance inside the block:
[weakSelf loadAssetToScrollView:assets];
void (^assetGroupEnumerator)… = ^(ALAssetsGroup *group, BOOL *stop) {
…
};
Why? To avoid retain cycles.

Referencing superview's methods

I'm making an application in Xcode, and running into some problems. I'm using the GameKit framework to allow for bluetooth communication between two iOS devices. The application is setup so that one of the devices is the "master" and the other is the "slave," changing it's screen content based on data received from the "master" device. The user can select whether to be the master or the slave, and when that choice is made, the other device automatically becomes the opposite role. This is all done in one view controller class. When a role is chosen, a subview is added to the baseViewController.
What my problem is, is that when the subview that is added, I would like to be able to send data using the methods in the baseViewController class. With the current setup, the device invoking the action becomeMaster:sender crashes.
What I've tried so far is,
BaseViewController:
-(IBAction)becomeMaster:(id)sender {
[self dataToSend:#"slave"]; //tells peer device to become slave, since this device is master
masterViewController = [[MasterViewController alloc] initWithNibName:#"MasterViewController" bundle:nil];
[masterViewController setBaseViewController:self];
[self.view addSubview:masterViewController.view];
}
-(void)dataToSend:(NSString *)direction {
//—-convert an NSString object to NSData—-
NSData* data;
NSString *str = [NSString stringWithString:direction];
data = [str dataUsingEncoding: NSASCIIStringEncoding];
[self mySendDataToPeers:data];
}
-(void)dataToSend:(NSString *)direction {
//—-convert an NSString object to NSData—-
NSData* data;
NSString *str = [NSString stringWithString:direction];
data = [str dataUsingEncoding: NSASCIIStringEncoding];
[self mySendDataToPeers:data];
}
//----------------------------------------------------------------------------//
- (void)receiveData:(NSData *)data fromPeer:(NSString *)peer inSession:(GKSession *)session context:(void *)context {
//—-convert the NSData to NSString—-
NSString* str;
str = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
[self useReceivedData:str];
[str release];
}
-(void)useReceivedData:(NSString *)str {
if ([str isEqualToString:#"forward"]) {
[slaveViewController.view setBackgroundColor:[UIColor blackColor]];
}
}
MasterViewController:
-(void)setBaseViewController:(BaseViewController *)bvc {
baseViewController = bvc;
}
-(IBAction)goForward:(id)sender {
actionLabel.text = #"goingForward";
[baseViewController dataToSend:#"forward"];
}
Most of that code is part of the standard Apple documentation/examples, but I included it for understanding the flow of logic.
I believe the problem originates to with the becomeMaster:sender and setBaseViewController:bvc methods. Could anyone help fix? Thanks so much!
What kind of crash are you getting? EXC_BAD_ACCESS? Try turning on NSZombieEnabled in your executable's arguments. It's difficult to say what could be causing the crash, but you might try changing your setBaseViewController: implementation to this:
-(void)setBaseViewController:(BaseViewController *)bvc {
[self willChangeValueForKey:#"baseViewController"];
[baseViewController autorelease]
baseViewController = [bvc retain];
[self didChangeValueForKey:#"baseViewController"];
}
And add [baseViewController release]; to MasterViewController's -dealloc method.
Keep in mind that it's not entirely necessary to have a custom setter for baseViewController. If you have the following property declaration in your header file:
#property (nonatomic, retain) BaseViewController *baseViewController;
And you use #synthesize baseViewController, the -setBaseViewController: method is already generated for you, with key-value observing support built in. If you aren't familiar with Objective-C 2.0 properties, I suggest reading Apple's documentation.

Reachability - Best practice before showing webView

I would like to check "reachability" before/when a webView is shown in my app.
So far I've included the reachbility.h/.m files as well as added the SystemConfiguration.framework to the project.
And that's about where the agreements I have found on the internet end, from all of the posts and blogs etc. etc. everyone has a different idea/opinion of what to do after that. Additionally, I have found a lot partial code snippets that aren't really a complete solution, on which reachibility methods to call etc. etc. how to use them etc.
I have also found that some warn that you should try to reconnect before checking reachability...but I haven't found a consensus or a full solution. My app seems to reconnect to wifi without any extra code... so I'm a litte confused here too...
Any help to clear the muddy waters would be appreciated. I'm just looking for a simple straightforward solution.
Answer Accepted: I would like to note to newbies who may read this q/a later... that you will want to do the following:
Add this into your .h file:
- (BOOL) connectedToNetwork: (NSString *) remoteServer;
- (void) appLoadError: (NSString *) altertTitle alertMessage: (NSString *) altertMsg;
And you will need to import these at the top of your .m file:
sys/socket.h
netinet/in.h
netinet6/in6.h
arpa/inet.h
ifaddrs.h
netdb.h
SystemConfiguration/SystemConfiguration.h
Correct me if it is wrong... It seems to work fine for me...
I have always used this method in my App Delegate when I need to require Internet access. I have tuned it for different access types over time and it has served me well. It is a variant of one of the many methods you can find after a quick Google search on this topic.
It is a tricky thing to come up with a hard and fast strategy around this. The platform itself offers different connectivity options that have pros and cons based on the needs of each specific application. The method I use below is just a general connectivity test meaning the device can reach the Internet via some connectivity mechanism.
- (BOOL) connectedToNetwork: (NSString *) remoteServer {
// Create zero addy
struct sockaddr_in zeroAddress;
bzero(&zeroAddress, sizeof(zeroAddress));
zeroAddress.sin_len = sizeof(zeroAddress);
zeroAddress.sin_family = AF_INET;
// Recover reachability flags
SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress);
SCNetworkReachabilityFlags flags;
BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
CFRelease(defaultRouteReachability);
if (!didRetrieveFlags){
NSLog(#"Error. Could not recover network reachability flags");
return NO;
}
BOOL isReachable = flags & kSCNetworkFlagsReachable;
BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired;
BOOL nonWiFi = flags & kSCNetworkReachabilityFlagsTransientConnection;
NSURL *testURL = [NSURL URLWithString: remoteServer];
NSURLRequest *testRequest = [NSURLRequest requestWithURL:testURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:20.0];
NSURLConnection *testConnection = [[NSURLConnection alloc] initWithRequest:testRequest delegate:self];
return ((isReachable && !needsConnection) || nonWiFi) ? (testConnection ? YES : NO) : NO;
}
I usually call this inside applicationDidFinishLaunching. If the check returns false, I usually generate an error message (see below). This is because Apple forbids exiting the application by any means other than the home button on the device.
...
else if(![self connectedToNetwork: [NSString stringWithFormat: #"http://%#:%#/", sharedSettings.server, sharedSettings.port]]){
[self appLoadError: #"No Internet Detected" alertMessage:#"This application requires an active Internet connection. No content is available."];
}
...
- (void) appLoadError: (NSString *) altertTitle alertMessage: (NSString *) altertMsg {
UIAlertView *loadErr = [[UIAlertView alloc] initWithTitle: altertTitle message: altertMsg delegate: self cancelButtonTitle: #"OK" otherButtonTitles: nil];
[loadErr show];
[loadErr release];
// Load static screen
UIImage *image = [UIImage imageNamed:#"Error_NoInternet.png"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[controller setNavigationBarHidden: YES animated: NO];
[window addSubview: imageView];
[imageView release];
}
Just a quick note, I believe that method is leaking an NSURLConnection on every call (at the bottom, testConnection).
You might want to use
+ (NSURLConnection *)connectionWithRequest:
(NSURLRequest *)request delegate:(id)delegate
instead.

iphone gps cllocation and making variables globally accessible

I'm pretty new to iPhone development and have been trying to work out how to include GPS information into an app I'm working on.
I've gone through the HelloThere tutorial, which is a great start
http://www.mobileorchard.com/hello-there-a-corelocation-tutorial/
And had no problems getting this to run on my iPhone. I then took the example and have since been trying to incorporate the GPS info into a much larger and more complicated app. The larger application has an existing function which will send a post request to the server, and I'd like to simply provide the location data, specifically the coordinate.latitude and coordinate.longitude to this function, if possible without altering it.
This is pretty trivial in the other languages I've worked with but it's turned out to be quite challenging in objective C.
Basically, as per the tutorial I have gotten to the point where I'm logging the location info,
//GPS stuff
- (void)locationUpdate:(CLLocation *)location {
//locationLabel.text = [location description];
locationString = [location description];
locationLabel.text = locationString;
locLat = [NSString stringWithFormat:#"%lf", location.coordinate.latitude];
locLong = [NSString stringWithFormat:#"%lf", location.coordinate.longitude];
}
but I can't figure out how I can then make the locLat and locLong variables available to other parts of the application. Pretty lame but I'm still a bit lost with objective C.
There are many ways to do this. The quick and dirty way (and some will frown upon it) is to just declare those as globals in this file and use extern to access them from other files.
Better is to make those #properties of the class, and provide a getter so you can access those from another class or part of the app. That does assume that this class will be available for other classes to access later on.
You also can use delegate to get information. And...
Thinking a bit more, I would probably store data like this someplace else, and will use this routine to update the value in that location (by using a setter of that class), so this method here would just get the location and then store it elsewhere.
You might want to read Scott Knaster's book on Objective C and Mac development for a primer on Obj C.
Here's how I recommend doing it:
Store lat/long in a dictionary and fire them off as strings bundled in a notification. Setup an observer in the application delegate and have the callback function store the lat/long in class properties of the application delegate and/or store them in the application defaults.
In your class where you acquire the coordinates:
- (void)locationUpdate:(CLLocation *)location {
NSString *locationString, *locLat, *locLong;
locationString = [location description];
locLat = [NSString stringWithFormat:#"%lf", location.coordinate.latitude];
locLong = [NSString stringWithFormat:#"%lf", location.coordinate.longitude];
NSDictionary *locationDictionary = [NSDictionary dictionaryWithObjectsAndKeys:locationString, #"description",
locLat, #"latitude", locLong, #"longitude", nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateSearchLocation"
object:self userInfo:locationDictionary];
}
In your application delegate class:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Listen for search coordinates broadcast
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(setCoordinates:)
name:#"updateSearchLocation" object:nil];
}
- (void)setCoordinates:(id)sender {
self.latitude = [[sender userInfo] objectForKey:#"latitude"];
self.longitude = [[sender userInfo] objectForKey:#"longitude"];
NSLog(#"location = %#", [[sender userInfo] objectForKey:#"description"]);
}
Dont forget to setup the class properties in the application delegate header file as NSString. You can then access the coordinates by calling directly from the application delegate:
YourAppDelegateClassName *appDelegate = [[UIApplication sharedApplication] delegate];
NSLog(#"lat = %#, long = %#", appDelegate.latitude, appDelegate.longitude);
Or you can access them anywhere from the user defaults:
[[NSUserDefaults standardUserDefaults] objectForKey:#"latitude"];
[[NSUserDefaults standardUserDefaults] objectForKey:#"longitude"];
I hope that helps.