Ma première mise à jour d'application a été mise en ligne la nuit dernière et j'ai reçu une plainte selon laquelle la mise à jour avait entraîné la disparition des données créées par l'utilisateur (certaines d'entre elles). J'ai pu reproduire le problème, mais je ne peux pas dire pourquoi.
Dans le répertoire Documents, j'ai enregistré un fichier de clé qui me dit le "titre" de tous les fichiers de l'utilisateur et leurs noms de fichiers (chemin complet). Ensuite, tous les fichiers de l'utilisateur sont également dans le répertoire Documents.
Lorsque la mise à jour est effectuée, le fichier de clé est toujours là (du moins, je pense que c'est parce que les données s'affichent sur le premier écran de l'application. Les applications se ferment et se relancent complètement après la mise à jour, n'est-ce pas?), Mais lorsque l'utilisateur essaie Pour naviguer dans les fichiers réels, il n’existe aucune donnée et les nouvelles données saisies par l’utilisateur ne sont jamais enregistrées.
Il agit exactement comme lors du débogage lorsque j'utilisais accidentellement un nom de fichier invalide (avec des caractères incorrects) - il n'a jamais été enregistré. Mais avec la mise à jour, ces fichiers avaient été correctement enregistrés dans l'ancienne version mais échouaient d'une manière ou d'une autre dans la nouvelle version.
Ceci est ma première application et ma première mise à jour et je suis tout à fait perdu ici. J'ai retiré l'application de la vente pour le moment (je ne savais pas que vous ne pouviez pas simplement revenir à une ancienne version! Beurk!) Et j'apprécierais énormément toute idée de l'endroit où/comment chercher le problème et comment écrire. une bonne mise à jour qui ne perdra pas les données. (Jusqu'à présent, tout ce que j'ai trouvé est "enregistrer les données dans le répertoire Documents", ce que je faisais déjà.)
L'application originale est enregistrée dans son propre projet et je peux y retourner et travailler à nouveau. J'ai copié tout ce répertoire quand j'ai commencé à travailler sur la mise à jour et je me demande si cela pourrait être le problème? J'ai changé le nom du répertoire qui contient tous les fichiers XCode et utilisé la fonction Projet> Renommer. Cela pourrait-il avoir cet effet?
L'application (à la fois d'origine et de mise à jour) fonctionne sous 4.2 et au-dessus, si cela compte.
RÉSOLUTION:
Je crois avoir résolu ce problème. Comme je l'ai dit au début de ma question, je sauvegardais le chemin complet des fichiers de l'utilisateur dans mes fichiers de clés. Apparemment, le chemin complet n’est PAS garanti après une mise à jour (je suis sûr que cela est documenté quelque part, mais je ne l’avais pas rencontré).
Ainsi, les fichiers de l’utilisateur avaient été transportés vers le nouveau répertoire Documents de la mise à jour, mais je les cherchais sur l’ancien chemin absolu, c’est-à-dire pas dans mon bac à sable.
Fixé en mettant une boucle dans didFinishLaunching de l'application pour extraire le fichier de chemins de fichiers incriminé (CELA, j'avais toujours cherché localement et cela fonctionnait toujours) et les découper en fichiers seulement. Le chemin d'accès aux documents doit être trouvé et ajouté par programme chaque fois que des opérations sur les fichiers sont effectuées.
Pour ce que ça vaut, c'était en fait bien pour moi qu'il n'y ait aucun moyen de revenir à un binaire précédent dans le magasin, car réinstaller la version d'origine n'aurait pas corrigé le problème de l'utilisateur, mais j'aurais cru que c'était le cas, du moins initialement. Je souhaite qu'il y ait un moyen d'avoir des mises à jour non autorisées, mais toujours autoriser de nouveaux achats (puisque le problème n'a pas affecté les nouveaux achats). Probablement pas une situation assez commune pour le justifier, cependant.
Juste pour éclairer un peu plus cette question pour les passants Internet. Oui, le PO a répondu à sa propre question à la toute fin. Vous ne devriez jamais stocker d'URL absolues pour les fichiers dans votre répertoire de documents, car cela pourrait provoquer des données loss . En effet, lorsque vous mettez à jour une application, en modifiant son numéro de version dans le fichier .plist, iOS crée un nouveau répertoire pour cette application avec un nom hexadécimal différent. Maintenant, votre URL absolue fait référence à l'emplacement incorrect et ne renvoie pas le fichier approprié.
Vous pouvez le voir sur votre propre ordinateur avant même de déployer sur un périphérique en accédant à
~/Bibliothèque/Application Support/iPhone Simulator/* ios_version */Applications /
Là, vous verrez des dossiers avec des noms comme:
6AA4B05C-8A38-4469-B7BE-5EA7E9712510 CB43C5F3-D720-49C3-87D4-EBE93FFD428B
À l'intérieur de ces dossiers se trouve la structure de système de fichiers standard pour les applications iOS. c'est à dire.
Documents Bibliothèque Tmp YourApp.app
En référençant l'URL entière, vous verrez quelque chose comme,
~/Bibliothèque/Support d'applications/iPhone Simulator/* ios_version */Applications/6AA4B05C-8A38-4469-B7BE-5EA7E9712510/Documents/MyVeryImportantUserData.txt
Toutefois, lorsque vous mettez à jour l'application, la nouvelle URL que l'application tentera sera la suivante:
~/Bibliothèque/Application Support/Simulateur iPhone/* ios_version */Applications/CB43C5F3-D720-49C3-87D4-EBE93FFD428B/Documents/MyVeryImportantUserData.txt
qui est vide.
Au lieu de cela, vous devez toujours créer une référence dynamique en enregistrant le chemin de fichier uniquement après avoir obtenu le préfixe de chemin de fichier du répertoire de documents.
/**
Returns the path to the application's Documents directory.
*/
- (NSString *)applicationDocumentsDirectory {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}
Sur l’affiche originale, vous pourriez avoir enregistré vos utilisateurs ont perdu des données en publiant une nouvelle mise à jour dans laquelle vous avez modifié votre code afin de prendre l’URL absolue et de tout couper dans la partie documents de la chaîne. Ensuite, vous pouvez préfixer le chemin de fichier avec l'URL du répertoire de documents approprié et l'application aurait trouvé les données.
L’affiche de la question et la première réponse ont été utiles pour clarifier ce qui se passait exactement.
En me basant sur leurs observations, je me suis rendu compte qu'il y avait (ce qui semble être) un changement de nom des dossiers dans le chemin menant au dossier Documents. Cela m’a amené à une solution dans laquelle je n’enregistre que les noms de fichiers des fichiers et crée une classe d’utilitaire pour récupérer la chaîne current fullPath du nom de fichier qui a été enregistré et qui est maintenant stockée dans le fichier current Dossier Documents après les mises à jour de l'application:
#import "StringUtils.h"
@implementation StringUtils
+ (NSString *)getFullDocumentUrl:(NSString *)fileName
{
return [NSString stringWithFormat:@"%@/%@",[self applicationDocumentsDirectory],fileName];
}
+ (NSString *)applicationDocumentsDirectory
{
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}
@end
Pour obtenir le chemin actuel du répertoire de documents
NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
Si vous souhaitez enregistrer l'emplacement d'un fichier de manière persistante, utilisez les fonctionnalités de signet de NSURL. Un signet est une structure de données opaque, enfermée dans un objet NSData, décrivant l'emplacement d'un fichier. Alors que les URL de chemin et de référence de fichier sont potentiellement fragiles entre les lancements de votre application, un signet peut généralement être utilisé pour recréer une URL dans un fichier, même dans les cas où le fichier a été déplacé ou renommé.
J'ai rencontré le même problème. Vous trouverez ci-dessous un exemple de code permettant de corriger vos noms de fichiers en effectuant une itération dans les fichiers de votre répertoire de documents et en remplaçant les informations de chemin de fichiers tout en laissant les noms de fichiers. Avant d’exécuter la dernière ligne pour modifier les noms de fichiers, je vous recommande d’utiliser NSLog pour vous assurer que c’est exactement ce que vous voulez dans votre updatedName.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory
NSFileManager *fm = [NSFileManager defaultManager];
NSArray *filenames = [fm contentsOfDirectoryAtPath:documentsPath error:nil];
//Match on the filepath leading up to docs directory
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^/\\S*Documents/"
options:NSRegularExpressionCaseInsensitive
error:nil];
for (NSString *fileName in filenames)
{
NSRange fullLength = NSMakeRange(0, [fileName length]);
//swap out the prepended directory structure with an empty string
NSString *updatedFileName = [regex stringByReplacingMatchesInString:fileName
options:0
range:fullLength
withTemplate:@""];
NSString *currentName = [NSString stringWithFormat:@"%@/%@",documentsPath,fileName];
NSString *updatedName = [NSString stringWithFormat:@"%@/%@",documentsPath,updatedFileName];
[fm moveItemAtPath:currentName toPath:updatedName error:nil];
}
Vous pouvez utiliser cette fonction pour trouver une nouvelle liste de documents
ex: c'est la première fois que vous construisez une application et enregistrez une photo dans cette URL
"fichier: ///var/mobile/Containers/Data/Application/D79E1373-883C-412B-B84E-5C1E47BD0BEC/Documents/Temp/Photo_65650205603482916.jpg"
après cela, vous reconstruisez l'application, le doc direct est modifié
fichier: /// var/mobile/Conteneurs/Données/Application/E387590D-B279-4C38-A601-65C6F7BC917D/Documents /
de sorte que vous ne pouvez pas ne pas télécharger quand utiliser l'ancienne URL
Lorsque vous téléchargez, vous pouvez faire ceci:
// you have photoURl
func getURLtoUpload(photoUrl:URL) {
let urlStr = photoUrl.lastPathComponent
let fileURL = self.getDocumentsDirectory().appendingPathComponent("Temp").appendingPathComponent("\(urlStr)")
// your url to upload here
let url = URL(string:fileURL)
}
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}