Gamekit and iPhone - ios

I have my app set up to send a custom level in a form of a array to another person during a p2p connection. The receiving device saves the array to file for later use. I set up gamekit in my application, it will successfully search and connect to another device without any problems. Though a problem arises when I send data to a device, the receiving device will receive the data (and save the custom level like it should) but it will immediately crash afterwords.
Here are my methods that I use to send and receive data.
-(void) sendDataToPeers:(NSData *) data
{
if (currentSession)
{
//send the data
[self.currentSession sendDataToAllPeers:data withDataMode:GKSendDataReliable error:nil];
//Alerting the user that the custom level has been sent.
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Sent!" message:#"Your custom level has been sent." delegate:self cancelButtonTitle:#"Close" otherButtonTitles:nil];
[alert show];
[alert release];
}
}
-(void) btnSend
{
//Data that will be sent
NSMutableData *theData = [NSMutableData data];
//Archiver
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:theData];
//Desired level to send
int theLevel =[[CTManager sharedInstance]getLevel];
//Path to the custom levels
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory=[paths objectAtIndex:0];
NSString *customLevelsSen = [documentsDirectory stringByAppendingPathComponent: [NSString stringWithFormat:#"customLevels"]];
//Custom levels array
NSArray *theLevels = [[NSArray alloc] initWithContentsOfFile: customLevelsSen];
//Gets the desired level array from array of custom levels
NSArray *myArray = [[NSArray alloc]initWithArray:[theLevels objectAtIndex:theLevel-51]];
//prepare data
[archiver encodeObject:myArray forKey:#"level"];
[archiver finishEncoding];
//send the data
[self sendDataToPeers:theData];
//cleanup
[archiver release];
[theLevels release];
[myArray release];
}
-(void) receiveData:(NSData *)data fromPeer:(NSString *)peer inSession:(GKSession *)session context:(void *)context
{
//Archiver
NSKeyedUnarchiver *archiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
//Gets the custom level in form of an array from data.
NSArray *level = [archiver decodeObjectForKey:#"level"];
[archiver finishDecoding];
[archiver release];
//Path to the array of custom levels
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory=[paths objectAtIndex:0];
NSString *customLevelsRec = [documentsDirectory stringByAppendingPathComponent: [NSString stringWithFormat:#"customLevels"]];
//Gets the array of custom levels
NSMutableArray *customLevelArray = [[NSMutableArray alloc] initWithContentsOfFile:customLevelsRec];
//Adds a new array to the array of custom levels
[customLevelArray addObject:level];
//Saves the array.
[customLevelArray writeToFile:customLevelsRec atomically:YES];
//cleanup
[customLevelArray release];
//Message saying a custom level has been recieved
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Received!" message:#"A custom level has been saved." delegate:self cancelButtonTitle:#"Close" otherButtonTitles:nil];
[alert show];
[alert release];
}
Testing this has been a pain since I don't have two devices of my own currently, so I send a beta build to my friend who inturns tests them (he has ipod and iphone). Any help with this is appreciated...
If I can't find the problem I will most likely send the entire xcode project to him and via screen share work with the project on his computer to efficiently build and test the application. And I will be able to use debug mode.

I don't know if you ever found an answer to this question or not, I hope you did. But if you didn't I highly recommend that you try the new features of the new SDK. Instead of going through the whole encode/decode process, they have made it simple by having you do the following (in your send methodology):
data = [NSKeyedArchiver archivedDataWithRootObject:anObject];
where anObject can be pretty much any object, array, dictionary, whatever...
In your receive methodology:
NSObject *object = [NSKeyedUnarchiver unarchiveObjectWithData:data];
where object can also be pretty much any object.
As far as the crash you are experiencing, have you verified on which line the crash occurs? Are you sure it happens in the code you posted? Or is it happening somewhere else?

I don't see anything wrong in your receiveData method.
Have you checked that the folder where you are trying to save the data (customLevels) exists?
I have succeeded to connect via an application using GameKit a device and the iPhone simulator. It's really handy to debug.
I haven't check if it was by bluetooth or wifi.

NSData* data = [#"TEXT" dataUsingEncoding:NSUTF8StringEncoding];
NSError *error = nil;
[self.session sendData:data toPeers:peerID withDataMode:GKSendDataReliable error:&error];
(void) receiveData:(NSData *)data fromPeer:(NSString *)peer inSession:(GKSession *)session context:(void *)context {
NSString* message = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];//#"TEXT"
NSString* nameOfTheTransmitter = [session displayNameForPeer:peer];// name who sent
}

Related

How To Move A File Out Of The Inbox Folder When Using Airdrop Between iOS Devices

I am sending database file successfully between iOS devices with the following code:
-(void) doSendDatabase {
UIView *viewTemp = [[UIView alloc] init];
viewTemp.frame = CGRectMake(0.0f, 0.0f, 300, 300);
NSString *currentDatabaseName;
// This is the full path and file name with ext
currentDatabaseName = [self.databases objectAtIndex:[[mainTableView indexPathForSelectedRow] row]];
NSURL *url = [[NSURL alloc] initFileURLWithPath:currentDatabaseName];
UIActivityViewController * airDrop = [[UIActivityViewController alloc]
initWithActivityItems:#[url]
applicationActivities:nil];
airDrop.popoverPresentationController.sourceView = self.view;
[self presentViewController:airDrop
animated:YES
completion:nil];
[url release];
[airDrop release];
[viewTemp release];}
This code works and the database successfully gets sent from the sending iOS device to the receiving device. However, the databases are stored in the Documents/Inbox folder (by design I suppose). I simply want to move the received database files from the Inbox folder up one level into the Documents folder. From what I'm reading I need to handle this in openURL in the App Delegate - but am not sure how to go about this. Any help would be greatly appreciated.
Thank you.
Ok - here's what I did to resolve the problem.
(1) I created a handleInboxItems method in the App Delegate.
-(bool) handleInboxItems {
bool success = YES;
// Get the DBAccess object
DBAccess *dbAccess = [[DBAccess alloc] init];
// Get the Func object
Func *funcObject = [[Func alloc] init];
NSMutableArray *docDatabases;
// get a list of all database files in the Documents/Inbox folder ans store them in the inboxDatabases array
NSMutableArray *inboxDatabases = [[NSMutableArray alloc] init];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *inboxDirectory = [documentsDirectory stringByAppendingPathComponent:#"Inbox"];
NSDirectoryEnumerator *directoryEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:inboxDirectory];
for (NSString *inboxFileAndPath in directoryEnumerator)
{
//check to see if any of the files in the inbox folder end in the database extension - if so then save it in the inboxDatabases array
if ([[inboxFileAndPath pathExtension] isEqualToString:#“dbext”])
{
[inboxDatabases addObject:[inboxDirectory stringByAppendingPathComponent:inboxFileAndPath]];
}
}
// now go through the inboxDatabases array and copy them from the Documents/Inbox folder to the Documents folder
// loop through all inbox database and see if any of the database names already exist in Documents - if so then we need to tack on a sequential number
for (NSString *inboxDatabaseFileAndPath in inboxDatabases)
{
NSString *inboxDatabaseName = [[inboxDatabaseFileAndPath lastPathComponent] stringByDeletingPathExtension];
// Get the databases array from the DBAccess class (from the Documents folder) - need to get each time since we are moving files in there
docDatabases = [dbAccess getAllDatabases];
// does the inbox database already exist in the documents folder?
NSUInteger arrayIndex = [docDatabases indexOfObject:[funcObject databaseNameToFullPathName:allTrim(inboxDatabaseName)]];
int i = 0;
while (arrayIndex != NSNotFound)
{
++i;
NSString *tempDatabaseName = [NSString stringWithFormat:[inboxDatabaseName stringByAppendingString:#" %d"],i];
// see if the database (with sequential number) already exists
arrayIndex = [docDatabases indexOfObject:[funcObject databaseNameToFullPathName:allTrim(tempDatabaseName)]];
if (arrayIndex == NSNotFound)
{
// it does not exist, we can use this name
inboxDatabaseName = tempDatabaseName;
}
}
// give it full path and extension
NSString *docDatabaseFileAndPathToWrite = [funcObject databaseNameToFullPathName:allTrim(inboxDatabaseName)];
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
success = [fileManager copyItemAtPath:inboxDatabaseFileAndPath toPath:docDatabaseFileAndPathToWrite error:&error];
if (success)
{
// delete the inbox database file
success = [fileManager removeItemAtPath:inboxDatabaseFileAndPath error:&error];
if (!success)
{
NSAssert1(0,#"Failed to delete inbox database:'%#'.",[error localizedDescription]);
}
}
else
{
NSAssert1(0,#"Failed to copy inbox database to documents folder:'%#'.",[error localizedDescription]);
}
}
[dbAccess release];
[funcObject release];
[inboxDatabases release];
return success;}
(2) Added a call to this new method in the didFinishLaunchingWithOptions in the App Delegate just in case there is anything stuck in the inbox upon startup.
(3) I added the openURL method to the App Delegate in order to call handleInboxItems. After done, I send a notification so that I can refresh my database list.
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{
bool success = [self handleInboxItems];
if (success)
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIF_DATABASE_AIRDROPPED object:self];
return success;}
That's it - works as I need it to.

How to access saved photos to CloudKit?

I am tying and succeeded to save a photo using CloudKit, at least I think I did, because I don't know a user friendly way to check if I am right. I am asking these in the scenario that the users makes a few photos and the photos are saved using cloudKit and then he deletes the app but theoretically he should still be able to access the data via some sort of interface provided by apple, am I right?
And here is the core that I am using:
- (void) saveToiCloudImageNamed: (NSString *)imageName andTimeCreated:(NSString *)timeCreated{
CKContainer *container = [CKContainer defaultContainer];
CKDatabase *privateDatabase = [container publicCloudDatabase];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths firstObject];
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:imageName];
NSURL *fileUrl = [[NSURL alloc] initFileURLWithPath:fullPath];
CKAsset *photoAsset = [[CKAsset alloc] initWithFileURL:fileUrl];
CKRecord *record = [[CKRecord alloc] initWithRecordType:#"Photo"];
record[#"asset"] = photoAsset;
record[#"name"] = timeCreated;
[privateDatabase saveRecord:record
completionHandler:^(CKRecord *record, NSError *error) {
if (error==nil) {
NSLog(#"The save was successful");
//Do something
}else{
NSLog(#"Error saving with localizedDescription: %#", error.localizedDescription);
NSLog(#"CKErrorCode = %lu", (long)[error code]);
if ([error code]==CKErrorNetworkFailure) {
double retryAfterValue = [[error.userInfo valueForKey:CKErrorRetryAfterKey] doubleValue];
NSLog(#"Error code network unavailable retrying after %f", retryAfterValue);
// NSTimer *timer = [NSTimer timerWithTimeInterval:retryAfterValue
// target:self
// selector:#selector(testOutCloudKit)
// userInfo:nil
// repeats:NO];
// [timer fire];
}
}
}];
}
At the moment there is no interface for accessing CloudKit data other than what you create yourself. Maybe you want to use iCloud documents instead.
When you save to the public database (as you are doing in the sample above) then you could access the data using the CloudKit dashboard. But that is only accessible by member in your Apple developer account.

Keep incresing memory allocation

In my iOS app implemented for save videos from the web. It keeps increasing the memory usage when downloading videos. I have inspect using profile in xcode and saw some malloc getting increase per video.
I am not familiar with profile stuff. I have released the receivedData NSMUtableData variable.
- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectry = [paths objectAtIndex:0];
NSLog(#"Succeeded! Received %d bytes of data",[receivedData length]);
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSString *filename = [NSString stringWithFormat:(#"video_%#.mp4"),videoURL];
[receivedData writeToFile:[documentsDirectry stringByAppendingPathComponent:filename ] atomically:YES];
receivedData = nil;
[receivedData release];
progress.hidden = YES;
}
App getting down its performance. How can i fix this issue.
You have not released receivedData. You have set the variable to nil before, so any message sent to receivedData goes to nirvana.
Also don't forget to handle cases when connectionDidFinishLoading is never called, you have to release it elsewhere too because of this.

Post data and get response from URL for login is not working

In my application, I have login process and for that, I'm passing the username and password to php script and getting response. But the problem is, after getting the response I'm not able to move on to the next view controller or show the message.Need some guidance to resolve this issue.
This is my current code.
- (IBAction)submit:(id)sender
{
NSString *url = [NSString stringWithFormat:#"http://indianpoliticalleadersmap.com/IOS/login/getres.php?username=%#&password=%#",usern.text,pass.text];
NSData *dataURL = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
NSString *strResult = [[NSString alloc] initWithData:dataURL encoding:NSUTF8StringEncoding];
NSLog(#"%#",strResult);
if ([strResult isEqualToString:#"succuss"])
{
UIAlertView *alert1 = [[UIAlertView alloc]initWithTitle:#"Message" message:#"loged in" delegate:self cancelButtonTitle:#"ok" otherButtonTitles:nil, nil];
[alert1 show];
[alert1 release];
}
}
If I print the response, I can see the success message but still I don't why its not working.I am not able to make out where I'm going wrong in my above code.
Thanks.
As I can see you are having two lines above your output so trim the string by \n and spaces.
strResult=[strResult stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"\n "]];
it will definetly work

NSMutableArray disappears after app kill or restart using NSKeyedArchiver

I have an app that is storing Task objects (custom class) inside of a NSMutableArray. The Task class conforms to the NSCoding and NSCopying protocols, and I have also implemented the encodeWithCoder and initWithCoder methods.
When the user adds a new task to an NSMutableArray list, I save the array using NSKeyedArchiver. The list populates a UITableView.
The data is being saved, and when I exit the app and reenter, the data is still there. When I use another app for a while and come back, the data is still there. However, when I "kill" the app in the multitasking task manage or restart the device, the data disappears. Here are some important code snippets:
#define kFilename #"epapsTasksFile"
.
- (NSString *)dataFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:kFilename];
}
- (void)viewDidLoad {
NSString *filePath = [self dataFilePath];
if([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
self.list = [[NSKeyedUnarchiver unarchiveObjectWithFile:kFilename] retain];
}
else {
self.list = [NSMutableArray arrayWithCapacity:1];
}
...
}
- (void)applicationWillResignActive:(NSNotification *)notification {
NSMutableArray *updatedList = [[NSMutableArray alloc] initWithArray:self.list];
[NSKeyedArchiver archiveRootObject:updatedList toFile:kFilename];
}
Why is my app not saving the data when the app is "killed" or the device is restarted? Also, it may be interesting to note that when I restart the iPhone simulator, the data stays in place.
You need to save the data
([NSKeyedArchiver archiveRootObject:updatedList toFile:kFilename];
in applicationWillTerminate delegate method as as well to save it on termination.
EDIT:
applicationWillTerminate is not gauranteed in IOS4.0 and above.
Best is to check the return status of archiveRootObject:toFile: and see if the data is stored properly. As you figured it out, it can be case with wrong file path.

Resources