Hallo Delphi-Entwickler,
wir haben ein Problem beim Einlesen von Einstellungen, die über ein MDM an iOS- bzw. iPadOS-Geräte verteilt werden und im NSUserDefaults-Objekt liegen. Unsere Einstellungen sind einfache Schlüsselwertpaare, z.B. „skalierung“ als Integer. Abgesehen davon erwarten wir bisher nur elementare Datentypen. (Integer, String, Boolean)
Als MDM kommt ein Jamf Pro bzw. Microsoft Intune zum Einsatz. In beiden Fällen sehen wir in unserer App den erwarteten Schlüssel, unter dem die Einstellungen zu finden sind, aber beim Auslesen der konkreten Werte zwingt die App ein nicht abfangbarer Fehler zu einem sofortigen Beenden.
Unser Vorgehen ist dabei wie folgt:
Wir holen uns mit
Code:
nUserDefaults := TNSUserDefaults.Wrap(TNSUserDefaults.OCClass.standardUserDefaults)
das entsprechende Objekt im Apple-Betriebssystem und greifen mit
Code:
nUserDefaults.objectForKey(StrToNSStr('
com.apple.configuration.managed'))
auf die verteilten MDM-Einstellungen zu. Bis zu diesem Punkt ist die Welt in Ordnung und obwohl die Rückgabe nur vom Datentyp Pointer ist, zeigt uns der Delphi-Debugger tatsächlich die erwartete Struktur korrekt an! (siehe Screenshot SC1, wir haben in unserem Test fünf Parameter, daher die 5 Elemente, die dort zu sehen sind)
Laut verschiedener Quellen erwarten wir an dieser Stelle ein NSDictionary mit den hinterlegten Schlüsselwertpaaren. Da der Debugger es ohne Typ korrekt darstellt wollten wir mit
Code:
nDictionaryPointer := TNSDictionary.Wrap(…)
die Rückgabe von objectForKey direkt umwandeln.
Mithilfe des Debuggers sieht man auch eine Änderung. Nach dieser Umwandlung liegt dahinter keine Struktur mehr für ihn, sondern lediglich eine Speicheradresse. Ob das nur eine Eigenart im Debugger oder tatsächlich ein entscheidender Hinweis ist, können wir nicht sicher sagen, aber es ist in jedem Fall auffällig.
Laut Delphi ist damit das Objekt in den richtigen Datentyp konvertiert und wir können mit objectForKey bzw. valueForKey auf die Daten zugreifen. Leider führt genau dieser Zugriff zum Absturz, ohne die Möglichkeit den Fehler abzufangen. Mithilfe von Auswerten sieht man die ominöse Fehlermeldung „Field not found“, was eigentlich nicht sein sollte. (siehe Screenshot SC2)
Letztlich gibt uns der Compiler den Weg vor und dennoch werden wir darauf hingewiesen, dass die Methode an dieser Stelle nicht zur Verfügung steht.
Ergänzend haben wir auch mit alternativen Möglichkeiten gespielt. Unter anderem das TNSDictionary.Wrap umgangen, indem wir aus der NSUserDefaults-Istanz direkt über dictionaryForKey anstatt objectForKey das NSDictionary laden. Das sollte die Konvertierung sparen, ändert aber leider nichts am Ergebnis.