I am not sure if sandbox is taking too long to update or if my code is funky.
I am simply grabbing the local players last entered score and adding another score to it and trying to post the result.
Here is my code:
- (void) reportScore: (int64_t) score forCategory: (NSString*) category
{
GKScore *scoreReporter = [[[GKScore alloc]initWithCategory:category] autorelease];
scoreReporter.value = score;
[scoreReporter reportScoreWithCompletionHandler:^(NSError *error) {
if (error != nil)
{
// handle the reporting error
NSLog(#"Error reporting score");
}
}];
}
-(void)postScore:(int64_t)score forCategory:(NSString *)category {
GKLeaderboard *query = [[GKLeaderboard alloc]init];
query.category = category;
if (query != nil)
{
[query loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
if (error != nil){
// Handle the error.
NSLog(#"Error loading scores");
}
if (scores != nil){
// Process the score.
int64_t newScore = query.localPlayerScore.value + score;
[self reportScore:newScore forCategory:category];
}
}];
}
[query release];
}
Thanks for any help.
EDIT: Sandbox leaderboard has the first score, but will not update the subsequent scores.
Having the same issue at my end. It will provide the score correctly for the first time in a session. After that, it keep sending back the same score even if we update the score in that session.
You need to check property of GKleaderBoard class.For Your Info. see below code.
GKLeaderboardViewController *leaderController = [[GKLeaderboardViewController alloc] init];
if (leaderboardController != NULL)
{
leaderController.category = self.currentLeaderBoard;
leaderController.timeScope = GKLeaderboardTimeScopeWeek;
leaderController.leaderboardDelegate = self;
[self presentModalViewController: leaderController animated: YES];
}
AND
you can also check apple docs for both GKLeaderBoard and GKAchievementViewController class below.
for GKLeaderBoard
http://developer.apple.com/library/ios/#documentation/GameKit/Reference/GKLeaderboard_Ref/Reference/Reference.html
for GKAchievementViewController
http://developer.apple.com/library/ios/#documentation/GameKit/Reference/GKAchievementViewController_Ref/Reference/Reference.html
Related
I am retrieving some data from an API resource and I want to store the result inside my City entity using Magical Record and when the process finish, reload a tableView in my ViewController with the results.
All is fine but when I start the app for the first time,dowload process is started and the data is saved in core data.
but the table view in my ViewControllers is empty.
If I launch the app after the first time
the tableView refresh correctly.
I don't know if the problem is in threads... Can anybody help me?
ViewController :
Here I start the request. When block is called, I store cities array and reload tableView
- (void)getCitiesFromDataStore {
[[APIManager sharedManager] getCitiesWithCompletion:^(NSArray *cities) {
_dataSourceArray = cities;
[self.citiesTableView reloadData];
} failure:^(NSError *error) {
NSLog(#"%#",error.localizedDescription);
}];
}
APIMAnager
- (void)getCitiesWithCompletion:(void (^)(NSArray *))succesBlock
failure:(void (^)(NSError *))errorBlock
{
NSArray *cachedCities = [City findAllCities];
if ([cachedCities count] == 0) {
[self GET:#"cities" parameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {
NSArray *results = responseObject[#"cities"];
[City MR_importFromArray:results];
[[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];
NSArray *cities = [City findAllCities];
succesBlock(cities);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
errorBlock(error);
}];
return;
}
// Si ya hay ciudades almacenadas en CoreData, devuelvo el
// succesblock con las ciudades de CoreData
succesBlock(cachedCities);
}
I have a Category also to manage actions with the City entity
City+DBOperations
+ (NSArray *)findAllCities
{
NSArray *cities = [City MR_findAll];
return cities;
}
I know you said you resolved it, but for others who might be coming here another thing you could try is wrapping the import in a saveWithBlock:completion: and do your find in the completion block.
Also make sure you know which context each method is using. It is often helpful to be explicit about that.
Therefore you could change it to (this is untested, but should give you the concept):
[self GET:#"cities" parameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {
NSArray *results = responseObject[#"cities"];
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
[City MR_importFromArray:results inContext:localContext];
} completion:^(BOOL contextDidSave, NSError *error) {
NSArray *cities = [User MR_findAllInContext:[NSManagedObjectContext MR_defaultContext]];
succesBlock(cities);
}];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
errorBlock(error);
}];
During the call I try to switch voice from internal speaker to Loud speaker on iOS device using pjsip 2.2 library. It returns TRUE as success, but physically it doesn't change sound destination.
I use the next code
- (BOOL)setLoud:(BOOL)loud {
if (loud) {
#try {
pjmedia_aud_dev_route route = PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER;
pj_status_t pj_status = pjsua_snd_set_setting(PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE,
&route, PJ_TRUE);
if (pj_status == PJ_SUCCESS) {
return YES;
}
else
{
return NO;
}
}
#catch (NSException *exception) {
return NO;
}
} else {
#try {
pjmedia_aud_dev_route route = PJMEDIA_AUD_DEV_ROUTE_EARPIECE;
pj_status_t pj_status = pjsua_snd_set_setting(PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE,
&route, PJ_TRUE);
if (pj_status == PJ_SUCCESS) {
return YES;
}
else
{
return NO;
}
}
#catch (NSException *exception) {
return NO;
}
}
}
Could you suggest how can we make this work?
With the introduction of iOS 7, you should now be using AVAudioSession to handle any audio management. It took me a long time to finally get this to work but I finally figured out the problem of why my audio was not automatically routing to my iPhone Speaker. The problem is that when you answer a call, pjsip was automatically overriding the AVAudioSessionPortOverride I was performing before the call is answered. To tackle this problem, you simply just have to override the output audio port AFTER answering the call.
To make my VoIP application work efficiently with the background mode, I decided to handle the audio routing in a custom callback method named on_call_state. This method, on_call_state, is called by pjsip when a call state has changed. As you can read here, http://www.pjsip.org/pjsip/docs/html/group__PJSIP__INV.htm, there are many different flags you can check for when a call state has changed. The states I used in this example are PJSIP_INV_STATE_CONNECTING and PJSIP_INV_STATE_DISCONNECTED.
PJSIP_INV_STATE_CONNECTING is called when a audio call connects to another peer.
PJSIP_INV_STATE_DISCONNECTED is called when a audio call ends with another peer.
static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
{
pjsua_call_info ci;
PJ_UNUSED_ARG(e);
pjsua_call_get_info(call_id, &ci);
PJ_LOG(3,(THIS_FILE, "Call %d state=%.*s", call_id,
(int)ci.state_text.slen,
ci.state_text.ptr));
if (ci.state == PJSIP_INV_STATE_CONNECTING) {
BOOL success;
AVAudioSession *session = [AVAudioSession sharedInstance];
NSError *error = nil;
success = [session setCategory:AVAudioSessionCategoryPlayAndRecord
withOptions:AVAudioSessionCategoryOptionMixWithOthers
error:&error];
if (!success) NSLog(#"AVAudioSession error setCategory: %#", [error localizedDescription]);
success = [session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&error];
if (!success) NSLog(#"AVAudioSession error overrideOutputAudioPort: %#", [error localizedDescription]);
success = [session setActive:YES error:&error];
if (!success) NSLog(#"AVAudioSession error setActive: %#", [error localizedDescription]);
} else if (ci.state == PJSIP_INV_STATE_DISCONNECTED) {
BOOL success;
AVAudioSession *session = [AVAudioSession sharedInstance];
NSError *error = nil;
success = [session setActive:NO error:&error];
if (!success) NSLog(#"AVAudioSession error setActive: %#", [error localizedDescription]);
}
}
how does my fetchedResultsController method look like, if I want to fetch all my attributes for an entity from core data? I only know and understand how to fetch data for a tableView and I think that is where all my confusion is coming from.
Here is my Core-Data setup:
I'm trying to fill an array with all the Attributes my Setting entity has and the show those values via NSLog output in my debug console.
Here is what I changed so far:
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *newEntry = [NSEntityDescription insertNewObjectForEntityForName:#"Setting" inManagedObjectContext:context];
//NSManagedObject *newSetting = [NSEntityDescription insertNewObjectForEntityForName:#"Setting" inManagedObjectContext:context];
[newEntry setValue: #"StudiSoft" forKey:#"settingName"];
if (_overrideSysTimeSwitch.on) {
[newEntry setValue: #YES forKey:#"settingSysTimeOverride"];
//editSetting.settingSysTimeOverride = #YES;
NSLog(#"IF A");
} else {
//[newEntry setValue: #NO forKey:#"settingSysTimeOverride"];
//editSetting.settingSysTimeOverride = #NO;
NSLog(#"IF B");
}
if (_timeFormatSwitch.on) {
//[newEntry setValue: #YES forKey:#"settingTimeFormat"];
//editSetting.settingTimeFormat = #YES;
NSLog(#"IF C");
} else {
//[newEntry setValue: #NO forKey:#"settingTimeFormat"];
//editSetting.settingTimeFormat = #NO;
NSLog(#"IF D");
}
[self.settingsArray addObject:#"StudiSoft"];
NSError *error;
[context save:&error];
I'm using this code-snipped that and I'm able to modify the core data content.
However, every time I run this code, it of course adds a new object.
I've been looking for a way to update existing Attributes in my Entity, or modify them, but I could NOT find them.
Anyhow this is a good step into the right direction.
I created a completely new project, with just one view, once I have it working on the main view I'm going to experiment with segues....
But for now, how would I update or change existing attributes?
Thanks guys!!
This is my editSave Method to store some data in core data:
- (IBAction)editSave:(UIBarButtonItem *)sender
{
if ([_editSaveButton.title isEqualToString:#"Edit"])
{
[self setTitle:#"Edit Settings"];
//self.title = #"Edit Settings";
_overrideSysTimeSwitch.userInteractionEnabled = YES;
_timeFormatSwitch.userInteractionEnabled = YES;
_editSaveButton.title = #"Save";
} else if ([_editSaveButton.title isEqualToString:#"Save"])
{
[self setTitle:#"Settings"];
//self.title = #"Settings";
_overrideSysTimeSwitch.userInteractionEnabled = NO;
_timeFormatSwitch.userInteractionEnabled = NO;
_editSaveButton.title = #"Edit";
// #############################################################
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
//NSManagedObject *newEntry = [NSEntityDescription insertNewObjectForEntityForName:#"Setting" inManagedObjectContext:context];
//[newEntry setValue: #"StudiSoft" forKey:#"settingName"];
/*NSString *firstName = [anEmployee firstName];
Employee *manager = anEmployee.manager;
Setting *newSetting = [NSString #"Test"];
[newSetting setValue:#"Stig" forKey:#"settingName"];
[aDepartment setValue:[NSNumber numberWithInteger:100000] forKeyPath:#"manager.salary"];*/
//editSetting.settingName = #"Test";
if (_overrideSysTimeSwitch.on) {
//[newEntry setValue: #YES forKey:#"settingSysTimeOverride"];
editSetting.settingSysTimeOverride = #YES;
NSLog(#"IF A");
} else {
//[newEntry setValue: #NO forKey:#"settingSysTimeOverride"];
editSetting.settingSysTimeOverride = #NO;
NSLog(#"IF B");
}
if (_timeFormatSwitch.on) {
//[newEntry setValue: #YES forKey:#"settingTimeFormat"];
editSetting.settingTimeFormat = #YES;
NSLog(#"IF C");
} else {
//[newEntry setValue: #NO forKey:#"settingTimeFormat"];
editSetting.settingTimeFormat = #NO;
NSLog(#"IF D");
}
//[self.settingsArray addObject:#"StudiSoft"];
NSError *error = nil;
//if ([self.managedObjectContext hasChanges]) {
//NSLog(#"SAVE & DISMISS conetx has changed");
if (![context save:&error]) { // save failed
NSLog(#"Save failed: %#", [error localizedDescription]);
} else { // save succeeded
NSLog(#"Save Succeeded");
}
//}
//[self.tableView reloadData];
// #############################################################
}
}
Debug Output:
2014-06-10 19:09:29.881 SettingsCoreData[508:60b] Entry #5: <Setting: 0x8f983e0> (entity: Setting; id: 0x8f97030 <x-coredata://FA78AB86-3225-4B1E-97DD-3F31F5323A18/Setting/p6> ; data: {
settingName = StudiSoft;
settingSysTimeOverride = 0;
settingTimeFormat = 0;
})
2014-06-10 19:09:29.883 SettingsCoreData[508:60b] Entry #6: <Setting: 0x8f98430> (entity: Setting; id: 0x8f97040 <x-coredata://FA78AB86-3225-4B1E-97DD-3F31F5323A18/Setting/p7> ; data: {
settingName = StudiSoft;
settingSysTimeOverride = 1;
settingTimeFormat = 1;
})
Now I should be able to use something like this in my viewDidLoad, right?
if (editSetting.settingSysTimeOverride.boolValue == 0) {
_overrideSysTimeSwitch.on = NO;
} else {
_overrideSysTimeSwitch.on = YES;
}
But it doesn't work as I thought it will :-(
Next you need to call -performFetch: on the NSFetchedResultsController. Make sure you check the response and handle the error if the response is NO.
From there your NSFetchedResultsController is populated and ready to be used. You can then grab individual elements via -objectAtIndex: or you can grab them all with -fetchedObjects.
I would suggest just reviewing the documentation on the methods that are available as it has pretty strong and clear documentation.
Update
If you are not receiving any data then break it down. Take the NSFetchRequest that you created and call -executeFetchRequest:error: against your NSManagedObjectContext and see if you get any data back.
If you do then there is something wrong with your handling of the NSFetchedResultsController.
If you don't then there is something wrong with your NSFetchRequest or you don't have any data in your store.
Update
Sounds like you need to read a book on how Core Data works.
A NSFetchRequest is a query against Core Data so that objects can be returned from the store. You can pass a NSFetchRequest to a NSFetchedResultsController so that the NSFetchedResultsController can monitor the store for changes and let your view controller know when those changes occur.
A NSFetchRequest can also be executed directly against the NSManagedObjectContext and you can retrieve the results directly. You do that by calling -executeFetchRequest:error: against your NSManagedObjectContext and getting a NSArray back. You can then check that NSArray to see if you get any results.
If you do not understand that paragraph then you need to take a step back and read the tutorials on Core Data and/or read a book on Core Data. I can recommend an excellent book on the subject ;-)
Is there a method (NSPredicate or other function) that returns ANY single existing NSManagedObject. Could also be the count of an entity type. No further requirements other than mere existence on self.
NSPredicate *fetch = [NSPredicate predicateWithFormat: "#ANY"]
....
[fetch setEntity:entityDescription];
[fetch setPredicate: predicate];
[fetch setFetchLimit:1];
Note that this is the 'root' object, thus no instance at this boot stage.
I am not sure if I understand your question correctly, but to get a one (arbitrary) object
of your entity just don't add a predicate to the fetch request and set the fetch limit to
one:
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"YourEntity"];
[request setFetchLimit:1];
NSError *error;
NSArray *result = [context executeFetchRequest:request error:&error];
if (result == nil) {
// Error executing fetch request
} else if ([result count] == 0) {
// Found none
} else {
// Found one
NSManagedObject *obj = result[0];
}
I'm coming across this a few years later & thought it might be helpful to see this in Swift. In my testing, this returns the first entry in the data store, not necessarily a random entry from the whole store or even a different one each time.
Assuming that by "ANY" you're OK simply returning the first entry, here's how to do it in Swift.
for Swift 4.2:
let fetchRequest : NSFetchRequest<yourEntityName> = yourEntityName.fetchRequest()
fetchRequest.fetchLimit = 1
do {
let fetchResults = try managedContext.fetch(fetchRequest)
if fetchResults.count == 0 {
// found none
} else {
// found one
var obj: NSManagedObject = fetchResults[0]
}
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
I have an app where I present VC1 to pick a game and VC2 to submit plays for the selected game. When a user segues back from VC2 to VC1 I want to retain the game data for the game they were playing. Since it's iOS 6.0, I am using UIManagedDocument to access Core Data for storing and retrieving the game data. And I am totally stumped by the problem I am facing and after spending countless hours, I am reaching out to the wise folks on this forum.
When I run the code below in the Simulator, everything works fine, the data gets stored and I am also able to retrieve it and show it if the user picks the same game as earlier on to play. Unfortunately on the device, I can see that the data gets stored on segue - I put a breakpoint and looked at the persistentStore using iExplorer - but as soon as I go back to VC2 selecting the stored game, the persistentStore seems to be overwritten or purged of all data. In the debugger I noticed that the _persistentStores NSArray property of the _persistentStoreCoordinator object for "UIManagedDocument" always shows 0 when retrieval is done on the device.
Any help is much appreciated!!!
- (void) addOrGetDataToGamesDatabase:(CNPUIManagedDocument *)document withFlag:(BOOL)getFlag {
if (getFlag) {
NSLog(#"INSIDE addDataToGamesDatabase to get data");
}
else
NSLog(#"INSIDE addDataToGamesDatabase to set data");
dispatch_queue_t update = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);
dispatch_sync(update, ^{
[document.managedObjectContext performBlockAndWait:^{
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"Game"];
request.predicate = [NSPredicate predicateWithFormat:#"game = %#", self.selectedGameID];
NSError *error = nil;
NSLog(#"Persistent Store Name = %#", [[document class] persistentStoreName]);
NSArray *matches = [document.managedObjectContext executeFetchRequest:request error:&error];
NSLog(#"Fetch Error if any: %# %#", error.debugDescription, [error userInfo]);
if (!matches || matches.count >1) {
NSLog(#"There is a problem with creating the game data");
}
//This is where it fails on the device as the match.count is always 0 as the fetch retrieves nothing
else if ([matches count] == 0) {
if (!getFlag) {
// Code to initialize the game data in store
}
}
else if ([matches count] == 1) {
// Another fetch - nested
if (!oTeammatches || [oTeammatches count] >1) {
NSLog(#"There is a problem with creating the offense team data");
}
else if ([oTeammatches count] == 0) {
if (!getFlag) {
//Code to initialize the team data in store
}
}
else if ([oTeammatches count] == 1) {
OTeam *newOTeam = [oTeammatches lastObject];
if (getFlag) {
//Retrieves data
//Shown by log lines beginning with "Getting"
}
else {
//Sets/Saves data
//Shown by log lines beginning with "Setting"
}
}
}
}];
if (!getFlag) {
[document updateChangeCount:UIDocumentChangeDone];
}
});
}
- (IBAction)pressBackButton:(UIButton *)sender {
[self addOrGetDataToGamesDatabase:self.gamesDatabase withFlag:NO];
if ((self.gamesDatabase.documentState & UIDocumentStateEditingDisabled) != UIDocumentStateEditingDisabled) {
[self.gamesDatabase saveToURL:self.gamesDatabase.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:^(BOOL success) {
if (success) {
NSLog(#"DB save file path: %#", self.gamesDatabase.fileURL);
NSLog(#"Saved!!!");
}
else
NSLog(#"Unable to save");
}];
}
[self performSegueWithIdentifier:#"BackToPickGame" sender:self];
}
- (void)viewDidLoad
{
[super viewDidLoad];
//Some Initialization code
if (!self.gamesDatabase) {
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
url = [url URLByAppendingPathComponent:#"GameDB"];
self.gamesDatabase = [[CNPUIManagedDocument alloc] initWithFileURL:url];
NSLog(#"DB File URL generated: %#", url);
NSLog(#"self.gameDatabase initialized");
}
[self addOrGetDataToGamesDatabase:self.gamesDatabase withFlag:YES];
NSLog(#"Calling game with ID %# , self.selectedGameID);
}
Some log info on the persistent store
DEVICE
First get on entering VC2
Printing description of document->_persistentStoreCoordinator:
Printing description of document->_persistentStoreCoordinator->persistentStores:
<_NSArrayM 0x1fd28ce0>(
)
First set in VC2 on exiting VC2
Printing description of document->_persistentStoreCoordinator:
Printing description of document->_persistentStoreCoordinator->persistentStores:
<_NSArrayM 0x1fd28ce0>(
(URL: file://localhost/var/mobile/Applications/4DD2D219-5AC1-406F-8020-260B01E46E0C/Documents/GameDB/StoreContent/persistentStore)
)
Second get on entering VC2
Printing description of document->_persistentStoreCoordinator:
Printing description of document->_persistentStoreCoordinator->persistentStores:
<_NSArrayM 0x211d4660>(
)
SIMULATOR
First get on entering VC2
Printing description of document->_persistentStoreCoordinator:
Printing description of document->_persistentStoreCoordinator->persistentStores:
<_NSArrayM 0x84e4b60>(
(URL: file://localhost/Users/Rujul/Library/Application%20Support/iPhone%20Simulator/6.0/Applications/B187169B-8D32-4BB1-AB41-33DB76637D9C/Documents/GameDB/StoreContent/persistentStore)
)
First set on exiting VC2
Printing description of document->_persistentStoreCoordinator:
Printing description of document->_persistentStoreCoordinator->persistentStores:
<_NSArrayM 0x84e4b60>(
(URL: file://localhost/Users/Rujul/Library/Application%20Support/iPhone%20Simulator/6.0/Applications/B187169B-8D32-4BB1-AB41-33DB76637D9C/Documents/GameDB/StoreContent/persistentStore)
)
Second get on entering VC2
Printing description of document->_persistentStoreCoordinator:
Printing description of document->_persistentStoreCoordinator->persistentStores:
<_NSArrayM 0xf777910>(
(URL: file://localhost/Users/Rujul/Library/Application%20Support/iPhone%20Simulator/6.0/Applications/B187169B-8D32-4BB1-AB41-33DB76637D9C/Documents/GameDB/StoreContent/persistentStore)
)
Check all the overwrites in your code (like above in UIDocumentSaveForOverwriting). Log the exact values before and after. I am sure you are going to find the culprit in this way.
Also, check what you are doing in each prepareForSegue:.
BTW, I would recommend to perhaps refactor the confusing addOrGetDataToGamesDatabase business into two easily understood methods.