What information does the game center return after finding players? - xcode

I am currently experimenting on raywenderlich's project of How To Make a Multiplayer iPhone Game Hosted on Your Own Server Part 1
at the end of the part 1 tutorial, it claims that after looking for auto-match via the game center panel, the log panel would show 2 PlayerIDs
CatRace[5407:707] didFindPlayers
CatRace[5407:707] G:1036727375
CatRace[5407:707] G:1417937643
However, when I tried to run on the iPhone Simulator and my iPhone, it always returns only 1 playerID after finished matching players.
So, I would like to know exactly how the function would return the information.
Could anyone help on this ?
Additional:
I found that the simulator and the iDevice found the player of another, but not including itself. Is it the normal case?
Already tried to put the server on to an external host. Still No luck, returning only one player in the array.
Is this function
- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindPlayers:(NSArray *)playerIDs
supposed to return all the players including the local player ?

Although it is so wired, I manage to manipulate the return into a new NSMUTABLEARRAY and send to the hosting server.
- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindPlayers:(NSArray *)playerIDs {
NSMutableArray *players = [[NSMutableArray alloc] initWithArray:playerIDs];
[players insertObject:[GKLocalPlayer localPlayer].playerID atIndex:0];
if (_state == NetworkStatePendingMatch) {
[self dismissMatchmaker];
[self sendStartMatch:players];
}
[players release];
However, I am still looking for the answer of my original question, which is the supposed return of - (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindPlayers:(NSArray *)playerIDs

Related

Cocoa - How to detect change in ubiquity container

I've got an OS X app syncing a single document through a ubiquity container back and forth to an iOS equivalent app. The iOS app receives data whenever it changes on the Mac side and sends it whenever it changes on the iOS side (so the iOS app is working all around), and the Mac app sends the data whenever it is changed on the Mac side and it receives the data when the app is launched, but it doesn't seem to be checking again for any data while it runs. I'd like it to update with any changes automatically and immediately, like the OS X "Notes" app does from changes on the iOS side.
At launch, this is the relevant function that gets called:
+(NSMutableDictionary *)getAllNotes {
if(allNotes == nil) {
allNotes = [[NSMutableDictionary alloc]initWithDictionary:[[NSUserDefaults standardUserDefaults] dictionaryForKey:kAllNotes]];
cloudDoc = [[CloudDocument alloc]initWithContentsOfURL:[self notesURL] ofType:NSPlainTextDocumentType error:nil];
[cloudDoc saveToURL:[self notesURL] ofType:NSPlainTextDocumentType forSaveOperation:NSSaveOperation error:nil];
}
return allNotes;
}
and that "CloudDocument" class (which is a subclass of NSDocument) includes:
#import "Data.h"
#implementation CloudDocument
-(NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError {
return [NSKeyedArchiver archivedDataWithRootObject:[Data getAllNotes]];
}
-(BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError {
NSDictionary *dict = (NSDictionary *)[NSKeyedUnarchiver unarchiveObjectWithData:(NSData *)data];
[Data didReceiveCloudData:dict];
return YES;
}
+(BOOL)autosavesInPlace {
return YES;
}
#end
which kicks it back to:
+(void)didReceiveCloudData:(NSDictionary *)d {
allNotes = [[NSMutableDictionary alloc]initWithDictionary:d];
[[NSUserDefaults standardUserDefaults] setObject:allNotes forKey:kAllNotes];
[cloudDoc updateChangeCount:NSChangeDone];
}
I think the problem is just that I don't have any part of my code that is equivalent to the phrase "check periodically to see if the ubiquity container has changed, and then do..." etc. I'm sure there's a well-known process for this (some notification event in NSDocument or something), but I've searched around and everything I find is either for iOS/UIDocuments instead of OS X/NSDocuments, or it's all theory and over my head without any tangible code samples to comb through and pick apart.
Can anyone help me out with a method for registering that an iCloud document in the ubiquity container has changed, and ideally where to put it (AppDelegate, CloudDocument.m, etc)? I only have one file syncing around, signified by the constant kAllNotes, so I don't need to track a bunch of different files or anything. I'm pretty sure I can use the code that runs at launch to do what needs to be done, I just can't figure out what to do to start the auto-syncing process.
Thank you in advance!
PS I'm still a beginner, so tutorials and code samples are much appreciated.
You're looking for NSMetadataQuery - it does a spotlight-like, continuously running search for any type of file - and is available on both iOS and OS X (indeed on iOS it can only be used for observing changes to the ubiquity container). I don't have any one link on how to use this - the Apple docs are too general to make much sense initially but do a search on 'NSMetadataQuery iCloud' and you should be sorted - there is tons of information out there on this topic.
With NSMetadataQuery you receive a notification every time something in the observed folder system changes, and it's not just applicable to UIDocument files even if a lot of examples are worried about UIDocuments.
Indeed, NSMetadataQuery it is - it feels like a hack but appears to be the only way to monitor changes to standard (non-UIDocument) files.
Here's a sample project I've compiled. It lets you upload an image from the camera roll, then monitors changes to the ubiquitous Documents folder:
https://github.com/versluis/iCloud-Images

Xcode- Alert if iPhone not charging [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
How to know when the device is charging?
I am kind of a noob at Xcode so sorry if I make I fool out of my self. I am trying to make an app and one of the functions is to check if the iphone/ipod/ipad is charging or not. If not charging I want it to play a sound perhaps and flash LEDs. Also if it is charging, I want to make it display text such as "Device Charging :) " . By the way I am using the method with the FlipsideViewController, but these features will be in the MainView. I have looked at various examples and have seen the one below as well as many test applications, but I don't know how to use it. Thank you in advance!!
Code:
[[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
if ([[UIDevice currentDevice] batteryState] != UIDeviceBatteryStateUnplugged) {
//Device is connected (charging or fully charged)
}
It sounds like you might want to start with some tutorials on writing iPhone apps because the code above looks ok (though I haven't tried this specifically). If you don't understand how to do some of the things I describe below (or some of the terms are unfamiliar), I'd recommend getting a good book or checking out some tutorials:
Book: iOS 6 SDK Development (Amazon)
Tutorials: Ray Wenderlich has many good tutorials on his site
Apple Documentation is quite good
There's no point in just writing the code for you because you presumably want to learn how to program and you won't learn much if someone just does it for you.
Here are some pointers on how to think about this, though the behavior you desire isn't completely obvious from what you've said.
If I understand you you want two different actions to happen when the main view is displayed.
To start with, why not get it to set the text string in a field to match the state of charging / not charging?
So you'd add a UILabel to the main view .xib file in Xcode and add an outlet to it in the view controller so that you can set it's text at runtime.
Then you'll want to call the first line above somewhere once to start monitoring (parameter is: YES) and again with NO to stop monitoring once the view goes away. If you look at the documentation for UIViewController at developer.apple.com near the top you'll see a list of methods that UIViewController implements. In this case you probably want to override (create your own version of) viewWillAppear and viewWillDisappear and put the setBatteryMonitoringEnabled call with YES and NO into these two methods respectively.
So that takes care of enabling / disabling battery status monitoring. Now you need to test the state and take action (this is call to batteryState in your code above).
One question about design which isn't obvious from your description is if you want to do this once when the view appears or if you want it to continually monitor the state.
If you want to do it once, you could put the call to the above in viewDidAppear, say, and then use the outlet to the UILabel to set the message in the label to "Charging" or "Not Charging" based on the result from the batteryState method.
If you want something that watches for changes in the state of charging then you need to subscribe to the notification and put your code to change the UILabel (or whatever you finally do in response to a change) in the handler for that notification.
You figure this out by reading the documentation for UIDevice at developer.apple.com or in Xcode's Organizer window's Documentation section. If you read the documentation for the UIDevice method batteryMonitoringEnabled you can see that the "See Also" section includes two entries for the notifications you can subscribe to to find out when the Level or the State changes: UIDeviceBatteryLevelDidChangeNotification and UIDeviceBatteryStateDidChangeNotification. To learn how to subscribe to notifications you'll want to look at NSNotificationCenter documentation.
Then once you get this working you can add your fancier alerts (be careful about putting them up repeatedly!) and sounds (though playing a sound when the battery isn't charging will use battery which is somewhat questionable.. just make sure not to do it repeatedly perhaps).
good luck!
Add this to the appDelegate.m
- (void)applicationDidBecomeActive:(UIApplication *)application{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(batteryStateDidChange:) name:UIDeviceBatteryStateDidChangeNotification object:nil];
[[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
}
- (void)applicationWillResignActive:(UIApplication *)application {
[[UIDevice currentDevice] setBatteryMonitoringEnabled:NO];
}
- (void)batteryStateDidChange(NSNotification*)notif {
// check the status here.
// See if it is charging, or not and respond to the change.
}
(edited to make code more explicit)

Why i can't upload pictures to my pasted events from my own iOS app?

i came across a strange problem, when i add pictures to an past event from web-end,everything is ok,however when i did that from my own iOS app, there's no exception,i just can't see the newly added image.Can't we add photos to the past events from mobile client? Anyone knows that.
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:image,#"source", nil];
[facebookDelegate requestWithGraphPath:[NSString stringWithFormat:#"%#/photos",self.eventID] andParams:params andHttpMethod:#"POST" andDelegate:self];
There's no errors,but i just can't see the uploaded pictures.
And another question, how to set event's profile picture with graph api? I used the following code:
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:image,#"picture", nil];
[facebookDelegate requestWithGraphPath:self.eventID andParams:params andHttpMethod:#"POST" andDelegate:self];
It also doesn't work.What's more, i want to konw if we can upload image from web,so we just offer the picture link to facebook ?
thanks.
i think you can try the first one now. It work now

Bring all NSDocument windows to front when opened

In most systems, the default behaviour for "open a new window" is that it appears at the front. This doesn't happen in Cocoa, and I'm trying to find the "correct" way to make this standard behaviour. Most things I've tried only work for a maximum of one window.
I need to open multiple windows on startup:
(N x NSDocuments (one window each)
1 x simple NSWindowController that opens a NIB file.
Things that DON'T work:
Iterate across all the NSDocuments I want to open, and open them.
What happens? ... only the "last" one that call open on comes to the front - the rest are hidden, invisible, nowhere on the screen, until you fast-switch or use the Window menu to find them.
Code:
...documents is an array of NSPersistentDocument's, loaded from CoreData...
[NSDocumentController sharedDocumentController];
[controller openDocumentWithContentsOfURL:[documents objectAtIndex:0] display:YES error:&error];
Manually invoking "makeKeyAndOrderFront" on each window, after it's opened
What happens? nothing different. But the only way I can find to get the NSWindow instance is so horribly hacky it seems totally wrong (but is mentioend in several blogs and mailing list posts)
Code:
[NSDocumentController sharedDocumentController];
NSDocument* openedDocument = [controller openDocumentWithContentsOfURL:[documents objectAtIndex:0] display:YES error:&error];
[[[[openedDocument windowControllers] objectAtIndex:0] window] makeKeyAndOrderFront:nil];
...I know I'm doing this wrong, but I can't find out why/what to do differently :(.
Something that works, usually, but not always:
As above, but just use "showWindow" instead (I took this from the NSDocument guide).
Bizarrely, this sometimes works ... even though it's the exact code that Apple claims they're calling internally. If they're calling it internally, why does it behave different if I re-invoke it after they've already done so?
[[[openedDocument windowControllers] objectAtIndex:0] showWindow:self];
You can just open all the documents without displaying and then tell the documents to show their windows:
NSArray* docs = [NSArray arrayWithObjects:#"doc1.rtf", #"doc2.rtf",#"doc3.rtf",#"doc4.rtf",nil];
for(NSString* doc in docs)
{
NSURL* url = [NSURL fileURLWithPath:[[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"] stringByAppendingPathComponent:doc]];
NSError* err;
[[NSDocumentController sharedDocumentController] openDocumentWithContentsOfURL:url display:NO error:&err];
}
[[[NSDocumentController sharedDocumentController] documents] makeObjectsPerformSelector:#selector(showWindows)];
Won't this work?
For 10.6 or greater
[[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];
This often has something to do with the app itself: your other windows are behind other apps (in particular, behind Xcode!), and would have appeared with a Hide Others command.
The solution to that problem would be that after you send showWindow to all of your windows (making sure you do the key one last), you tell the app to come forward, relative to other apps.
NSApp.activateIgnoringOtherApps(true) // Swift
or
[NSApp activateIgnoringOtherApps:YES]; // Objective-C
See also: How to bring NSWindow to front and to the current Space?

How do I set the default selection for NSTreeController at startup?

The Background
I've built a source list (similar to iTunes et al.) in my Cocoa app.
I've got an NSOutlineView, with Value
column bound to arrangedObjects.name
key path of an NSTreeController.
The NSTreeController accesses
JGSourceListNode entities in a Core
Data store.
I have three subclasses of
JGSourceListNode - JGProjectNode,
JGGroupNode and JGFolderNode.
I have selectedIndexPaths on NSTreeController bound to an NSArray called selectedIndexPaths in my App Delegate.
On startup, I search for group nodes and if they're not found in the core data store I create them:
if ([allGroupNodes count] == 0) {
JGGroupNode *rootTrainingNode = [JGGroupNode insertInManagedObjectContext:context];
[rootTrainingNode setNodeName:#"TRAIN"];
JGProjectNode *childUntrainedNode = [JGProjectNode insertInManagedObjectContext:context];
[childUntrainedNode setParent:rootTrainingNode];
[childUntrainedNode setNodeName:#"Untrained"];
JGGroupNode *rootBrowsingNode = [JGGroupNode insertInManagedObjectContext:context];
[rootBrowsingNode setNodeName:#"BROWSE"];
JGFolderNode *childFolder = [JGFolderNode insertInManagedObjectContext:context];
[childFolder setNodeName:#"Folder"];
[childFolder setParent:rootBrowsingNode];
[context save:nil];
}
What I Want
When I start the app, I want both top level groups to be expanded and "Untrained" to be highlighted as shown:
My Window http://synapticmishap.co.uk/Window.jpeg
The Problem
I put the following code in the applicationDidFinishLaunching: method of the app delegate:
[sourceListOutlineView expandItem:[sourceListOutlineView itemAtRow:0]];
[sourceListOutlineView expandItem:[sourceListOutlineView itemAtRow:2]];
NSIndexPath *rootIndexPath = [NSIndexPath indexPathWithIndex:0];
NSIndexPath *childIndexPath = [rootIndexPath indexPathByAddingIndex:0];
[self setSelectedIndexPaths:[NSArray arrayWithObject:childIndexPath]];
but the outline view seems to not have been prepared yet, so this code does nothing.
Ideally, eventually I want to save the last selection the user had made and restore this on a restart.
The Question
I'm sure it's possible using some crazy KVO to observe when the NSTreeController or NSOutlineView gets populated then expand the items and change the selection, but that feels clumsy and too much like a work around.
How would I do this elegantly?
Elegantly? This isn't elegant but it's how I'm doing it. I just do it manually. At app quit I write this value to user defaults:
lastSelectedRow = [outlineView selectedRow]
Then at app launch I run this in app did finish launching:
[self performSelector:#selector(selectLastNoteOrCreateDefaultNote) withObject:nil afterDelay:1];
Notice I just use a delay because I noticed the same as you that "the outline view seems to not have been prepared yet". Then in that selector I use this.
[outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:lastSelectedRow] byExtendingSelection:NO];
It works but better (more elegant) solutions are welcome from me too.

Resources