Mac Catalyst game crashes on GKAchievementInternal showBanner - game-center

Every time I submit an achievement to Game Center on macOS, using Mac Catalyst, my game crashes with this:
-[GKAchievementInternal showBanner]: unrecognized selector sent to instance 0x600002616ca0
No call stack. I set a break point for all the Obj-C exceptions but it's just stopped in the AppDelegate.
Everything is fine on iOS and iPadOS, and the rest of the Game Center behaviour on macOS seems to be fine.
For reference, this is how I submit the achievements:
private func submitAchievements(_ aList: [Achievement]) {
if !isGameCenterEnabled {
return
}
var achievements : [GKAchievement] = []
for kvp in AchievementFromId {
if aList.contains(kvp.1) {
let achievement = GKAchievement(identifier: kvp.0)
achievement.showsCompletionBanner = true
achievement.percentComplete = 100.0
achievements.append(achievement)
}
}
if achievements.count > 0 {
GKAchievement.report(achievements, withCompletionHandler: { (error: Error?) -> Void in
if let err = error {
NSLog("submitAchievements: \(err.localizedDescription)")
}
})
}
}
That function uses these data structures:
enum Achievement : Int {
case
clearTutorial = 0x00000001,
clearLevel1 = 0x00000002,
clearLevel2 = 0x00000004,
}
let AchievementFromId : [String : Achievement] = [
"Tutorial": .clearTutorial,
"Level1": .clearLevel1,
"Level2": .clearLevel2,
]
Edit:
I filed a feedback with the Feedback Assistant. In the meantime, the only workaround I found is disabling the completion banners on macOS:
#if targetEnvironment(macCatalyst)
achievement.showsCompletionBanner = false
#else
achievement.showsCompletionBanner = true
#endif
Also, to reset the achievements and test this, I use this function:
GKAchievement.resetAchievements() { error in
if let error = error {
NSLog("resetAchievements: \(error.localizedDescription)")
} else if let fn = onCompletion {
syncAchievements() // function that resubmits all the achievements again
}
}

This was a bug in macOS Catalina. Apple has resolved this in macOS 11 Big Sur (Feedback reference: FB7847659)
They don't have plans to fix this on Catalina.
For Catalina, just avoid showing banners with achievement.showsCompletionBanner = false. This looks a bit ugly, but I did this:
#if targetEnvironment(macCatalyst)
let os = ProcessInfo().operatingSystemVersion
achievement.showsCompletionBanner = os.majorVersion >= 11
#else
achievement.showsCompletionBanner = true
#endif
Note that I use ProcessInfo() because for some reason if #available(macOS 11.0, *) returns true in Catalina as well.

Related

CheckForDuplicateEntries': is not a member of 'Microsoft::WRL::Details (C2039)

I am programming a DirectX Game and on Debug mode it's working normally,
but on release mode I get 46 Errors of this:
Severity Code Description Project File Line Suppression State Error C2039 'CheckForDuplicateEntries': is not a member of 'Microsoft::WRL::Details' DirectXGame D:\Windows Kits\10\Include\10.0.17763.0\winrt\wrl\module.h 1427
I looked into the module.h code and saw this code:
void VerifyEntries() throw()
{
// Walk the linker generated list of pointers to CreatorMap for WinRT objects
for (const Details::CreatorMap** entry = GetMidEntryPointer() + 1; entry < GetLastEntryPointer(); entry++)
{
if (*entry == nullptr)
{
continue;
}
const wchar_t* name = ((*entry)->activationId.getRuntimeName)();
(name);
// Make sure that runtime class name is not nullptr and it has no empty string
__WRL_ASSERT__(name != nullptr && ::wcslen(name) != 0);
}
Details::CheckForDuplicateEntries((GetFirstEntryPointer() + 1), GetMidEntryPointer(),
[](const Details::CreatorMap* entry, const Details::CreatorMap* entry2) -> void {
__WRL_ASSERT__(entry->activationId.clsid != entry2->activationId.clsid && "Duplicate CLSID!");
}
);
Details::CheckForDuplicateEntries((GetMidEntryPointer() + 1), GetLastEntryPointer(),
[](const Details::CreatorMap* entry, const Details::CreatorMap* entry2) -> void {
__WRL_ASSERT__(::wcscmp((entry->activationId.getRuntimeName)(), (entry2->activationId.getRuntimeName)()) != 0 && "Duplicate runtime class name!");
}
);
}
But CheckForDuplicateEntries is only allowed on Debug mode:
#ifdef _DEBUG
template<typename T>
inline void CheckForDuplicateEntries(const CreatorMap** firstEntry, const CreatorMap** lastEntry, T validateEntry) throw()
{
__WRL_ASSERT__(firstEntry <= lastEntry);
if (firstEntry == lastEntry)
{
return;
}
for (const CreatorMap** entry = firstEntry; entry < (lastEntry - 1); entry++)
{
if (*entry == nullptr)
{
continue;
}
// Walk the linker generated list of pointers to CreatorMap
for (const CreatorMap** entry2 = (entry + 1); entry2 < lastEntry; entry2++)
{
if (*entry2 != nullptr)
{
(validateEntry)(*entry, *entry2);
}
}
}
}
#endif // _DEBUG
Does anyone know how I can get rid of this error?
I tried to remove the #endif define and of course it worked but only in visual studio and no where else.
I'm using vs2019, iso c++ 17, SDK 10.0.17763.0,
Thank you for helping!
SOLUTION: Updated SDK version from 10.0.17763.0 to 10.0.20348.0
Windows SDK (17763) is not the 'latest' version.
This specific issue is fixed in the Windows SDK (18362) or later, so I suggest installing a newer version and/or making sure your selection of Windows SDK in the build properties points to the newer one.
At this point, I'd recommend not using any build older than Windows SDK (19041).
https://developer.microsoft.com/en-us/windows/downloads/sdk-archive/

Cannot assign value of type '[NORScannedPeripheral]' to type '[third]'

I have downloaded a source code from https://github.com/NordicSemiconductor/IOS-nRF-Toolbox and I have added this to my project. Then I have created another class named "scanclassone" in my project and copied the codes in NORScannedPeripheral
to scan scanclassone.
Then I have came with an error "Cannot assign value of type '[NORScannedPeripheral]' to type '[scanclassone]'
func centralManagerDidUpdateState(_ central: CBCentralManager) {
guard central.state == .poweredOn else {
print("Bluetooth is porewed off")
return
}
let connectedPeripherals = self.getConnectedPeripherals()
var newScannedPeripherals: [NORScannedPeripheral] = []
connectedPeripherals.forEach { (connectedPeripheral: CBPeripheral) in
let connected = connectedPeripheral.state == .connected
let scannedPeripheral = NORScannedPeripheral(withPeripheral: connectedPeripheral, andIsConnected: connected )
newScannedPeripherals.append(scannedPeripheral)
}
peripherals = newScannedPeripherals
let success = self.scanForPeripherals(true)
if !success {
print("Bluetooth is powered off!")
}
}
I'm using Swift 4

App Crashed due to Invalid signature for pointer dequeued from free list in UIImagePickerController

I am facing problem in UIImagePickerController selection. When I choose source from Photo Library App crashes due to Invalid signature for pointer dequeued from free list. then If I run again it works fine with the same code. I searched on google and found one question related to my query Xcode - My app crash and the error is "Invalid pointer dequeued from free list *** set a breakpoint in malloc_error_break to debug" .
but solution isn't working in my case.
I am using Xcode 8.1 and my deployment Target is 8.0.
As #luke requested for the code for UIImagePickerViewController:
let pickerView = UIImagePickerController()
pickerView.delegate = self
pickerView.allowsEditing = true
pickerView.sourceType = .photoLibrary
let authStatus = PHPhotoLibrary.authorizationStatus() // Get the current authorization state.
// print(authStatus)
if (authStatus == PHAuthorizationStatus.notDetermined) {
// Access has not been determined.
PHPhotoLibrary.requestAuthorization({ (newStatus) in
if (newStatus == PHAuthorizationStatus.authorized) {
self.present(pickerView, animated: true, completion: { _ in })
}
else {
}
})
} else if authStatus == PHAuthorizationStatus.authorized {
print("Access has been granted.")
self.present(pickerView, animated: true, completion: { _ in })
} else if (authStatus == PHAuthorizationStatus.denied) {
print("Access has been denied.")
}
else if (authStatus == PHAuthorizationStatus.restricted) {
print("Restricted access - normally won't happen.")
}
Now when the user picks a particular image:
This method will be called:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
//print(info)
if let pickedImage = info[UIImagePickerControllerEditedImage] as? UIImage {
YOUR_GLOBAL_IMAGE_VIEW?.contentMode = .scaleAspectFit
YOUR_GLOBAL_IMAGE_VIEW?.image = pickedImage
}
}
dismiss(animated: true, completion: nil)
}
Don't forget to import PhotosUI and UIImagePickerControllerDelegate.

Swift PrepareForSegue ERROR Thread 1: EXC_BREAKPOINT(code=EXC_ARM_BREAKPOINT, subcode=0xdefe

I have really big problems when i try to compile my PrepareForSegue function:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "findMap" {
let MapViewController = segue.destinationViewController as UIViewController
if sender as UITableView == self.searchDisplayController!.searchResultsTableView {
let indexPath = self.searchDisplayController!.searchResultsTableView.indexPathForSelectedRow()!
let destinationTitle = filteredDepartments[indexPath.row].name
MapViewController.title = destinationTitle
} else {
let indexPath = self.tableView.indexPathForSelectedRow()!
let destinationTitle = departments[indexPath.row].name
MapViewController.title = destinationTitle
}
}
}
The error opens in the Thread section in the "trap"-row:
--> 0x2f6e18: trap
and the error code is as above:
--> Thread 1: EXC_BREAKPOINT(code=EXC_ARM_BREAKPOINT, subcode=0xdefe
I think the error is in this line:
if sender as UITableView == self.searchDisplayController!.searchResultsTableView {
Bur i don't know how to solve it , so please help me ...
It's hard to tell what your code is supposed to mean, but my guess is that you mean this:
if sender === self.searchDisplayController!.searchResultsTableView {
Notice the use of the triple-equals operator to mean "is the same object as".

wxDirDialog Returns the Wrong Directory on Vista

I recently ported the following code to wx3.0 under visual studio 2013:
void PanelFileControl::on_retrieve_clicked(wxCommandEvent &event)
{
if(!chosen_files.empty())
{
Csi::ModalCounter counter;
wxDirDialog query(
this,
make_wxString(my_strings[strid_choose_retrieve_dir]),
make_wxString(wxGetApp().get_config()->get_last_prog_dir()));
int rcd;
query.CentreOnParent();
rcd = query.ShowModal();
if(rcd == wxID_OK)
{
// we need to generate an operation for every selected file.
StrAsc path(make_StrAsc(query.GetPath()));
DlgFileControl::operations_type operations;
if(path.last() != Csi::FileSystemObject::dir_separator())
path.append(Csi::FileSystemObject::dir_separator());
for(files_type::iterator fi = chosen_files.begin(); fi != chosen_files.end(); ++fi)
{
file_type const &file(*fi);
StrAsc file_path(path + file.get_file_name());
bool use_file(true);
if(Csi::file_exists(file_path.c_str()))
{
OwxStringStream message;
message << boost::format(my_strings[strid_overwrite_file_confirm].c_str()) %
file_path;
wxMessageDialog overwrite_query(
this,
message.str(),
wxT(""),
wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION);
int rcd;
overwrite_query.CentreOnParent();
rcd = overwrite_query.ShowModal();
if(rcd != wxID_YES)
use_file = false;
}
if(use_file)
operations.push_back(new ReceiveFileOperation(file, file_path));
}
// we can now display the operation dialogue
if(!operations.empty())
{
DlgFileControl dialogue(this, device_name, operations);
dialogue.show_modal();
}
}
}
} // on_retrieve_clicked
Following this change (which didn't require any changes to the code above), I have received complaints that, if the user selects the desktop and then double clicks on a directory on the desktop, that the file save operation fails. This appears to be a result of the path produced by the wxDirDialog::GetPath() and has only been seen under windows vista. I have followed up some testing and I find that, under Vista, the last path component is mentioned twice in the string returned by GetPath().
Has anyone seen this issue? Are there any work arounds?
I found that I can address the issue by preventing the wxDirDialog from using the IFILEDIALOG interface from being used. My ShowModal() method now looks like this:
int wxDirDialog::ShowModal()
{
WX_HOOK_MODAL_DIALOG();
wxWindow* const parent = GetParent();
WXHWND hWndParent = parent ? GetHwndOf(parent) : NULL;
// Use IFileDialog under new enough Windows, it's more user-friendly.
int rc;
#if wxUSE_IFILEDIALOG
if ( wxGetWinVersion() > wxWinVersion_Vista )
{
rc = ShowIFileDialog(hWndParent);
}
else
{
rc = wxID_NONE;
}
if ( rc == wxID_NONE )
#endif // wxUSE_IFILEDIALOG
{
rc = ShowSHBrowseForFolder(hWndParent);
}
// change current working directory if asked so
if ( rc == wxID_OK && HasFlag(wxDD_CHANGE_DIR) )
wxSetWorkingDirectory(m_path);
return rc;
}

Resources