* Важное обновление
Apple добавила дополнительное правило для приложений, представляемых в магазине приложений.
Мы больше не можем хранить произвольные файлы данных в папке «Документы».Только содержимое, сгенерированное пользователем, например текстовый файл, который он вручную набрал и сохранил, или фотография, сделанная камерой, могут быть сохранены в папке «Документы».
Теперь мы должны хранить файлы, созданные в приложении, в Библиотека / Кэш вместо папки «Документы».Кроме того, мы должны отметить файлы, которые мы не хотим синхронизировать с iCloud, с помощью атрибута skip backup .
Невыполнение этого требования приведет к отклонению приложения Apple.
Причина: теперь используется папка «Документы»для синхронизации с iCloud.iCloud выполняет синхронизацию каждые несколько минут, и если бы нам нужно, чтобы мегабайты файлов, сгенерированных нашим приложением, сохранялись в папке «Документы», он смешивался с собственными синхронизированными файлами iCloud пользователя.
Обновление MediaDirectory.m файлы с этим новым кодом для безопасности:
+ (NSString *) mediaPathForFileName:(NSString *) fileName
{
NSArray *directoryPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachesDirectory = [directoryPaths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:@"%@/%@", cachesDirectory, fileName];
return filePath;
}
+ (BOOL)addSkipBackupAttributeToFile:(NSString *) fileName
{
NSArray *directoryPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachesDirectory = [directoryPaths objectAtIndex:0];
NSString *filePathStr = [NSString stringWithFormat:@"%@/%@", cachesDirectory, fileName];
const char* filePath = [filePathStr fileSystemRepresentation];
const char* attrName = "com.apple.MobileBackup";
u_int8_t attrValue = 1;
int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
return result == 0;
}
Не забудьте пометить тот текстовый файл, который мы сгенерировали, с помощью атрибута пропуска резервного копирования, например, после создания файла:
[MediaDirectory addSkipBackupAttributeToFile:@"fileStatus.txt"];
У меня также была опечатка ранее, я сказал записать в файл "firstLaunch.txt", когда он должен был быть "fileStatus.txt" (плохие навыки копирования и вставки: P)
Оригинальный текст
Вы можете попробовать записать значение (например, «нет») в текстовый файл и сохранить его в папке «Песочница» приложения, когда пользователь нажимает кнопку «Больше не спрашивать».
В следующий раз, когда приложение загрузится, ваш контроллер представления прочитает значение из этого текстового файла и, если оно «нет», не будет отображать предупреждение.
Надеюсь, это поможет.
Написание однократного представления предупреждений пользовательского интерфейса
ОК, позвольте мне сначала объяснить процесс, который мы собираемся пройти:
1) Метод делегата приложения didFinishLaunchingWithOption является методомкоторый вызывается при запуске приложения.
2) Этот метод вызывается только один раз при запуске приложения, поэтому именно здесь мы создаем текстовый файл, и мы записываем наш статус представления оповещения: "показать снова "или" не показывать снова "для UIAlertView
3) Мы собираемся вызвать представление предупреждений в методе viewDidLoad вашего UIViewController.Однако мы только отображаем этот UIAlertView, ЕСЛИ значение в нашем текстовом файле НЕ «больше не показывать».Если значение в текстовом файле «показать снова», мы показываем UIAlertView, если это «не показывать снова», мы не показываем UIAlertView, имеет смысл?
(Эти значения толькоСтрока, вы можете установить любое значение, которое вы хотите, я использую только эти случайные значения для демонстрации).
Правильно, теперь мы получили общий процесс, давайте реализуем его.
Код
В вашем заголовочном файле AppDelegate.h:
@interface MyAppDelegate : NSObject
{
...
bool isFirstLaunch;
}
Теперь в вашем файле реализации AppDelegate.m:
// -------------------------------------------------------------------------------------
// I wrote a helper class called "MediaDirectory" that returns me the path to a file
// in the Documents directory of the application sandbox.
// Each application has a copy of the Documents directory so you can safely
// assume this directory will always exist.
//
// This class has been very useful for me, hope you find it useful too.
//
// DOWNLOAD THE FILES AT:
//
// http://www.chewedon.com/classes/MediaDirectory.h
// http://www.chewedon.com/classes/MediaDirectory.m
// -------------------------------------------------------------------------------------
#import <Foundation/NSFileManager.h>
#import <Foundation/NSFileHandle.h>
#import "MediaDirectory.h"
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
NSString *fileStatus = nil;
// Here, the NSFileManager defaultManager fileExistsAtPath method needs a path to
// the file in the Document directory, to get this path, use the static method from
// my MediaDirectory class and pass it the name of the file.
// I called it "fileStatus.txt"
//
// We're checking if the file exist in the Documents directory or not.
// If it does not exist then we create the text file and pass it the
// value "show again", otherwise we do nothing.
// (We don't want to overwrite the value everytime the app starts)
if([[NSFileManager defaultManager] fileExistsAtPath:[MediaDirectory mediaPathForFileName:@"fileStatus.txt"]] == NO)
{
// prepare fileStatus.txt by setting "show again" into our string
// we will write this string into the text file later
fileStatus = [[NSString alloc] initWithString:@"show again"];
// now we write the value "show again" so that the UIAlertView will show
// when it checks for the value, until the user clicks on no and we set
// this value to "don't show again" later in another piece of code
[fileStatus writeToFile:[MediaDirectory mediaPathForFileName:@"fileStatus.txt"]
atomically:YES
encoding:NSUTF8StringEncoding
error:nil];
}
[fileStatus release];
...
// rest of your didFinishLaunchingWithOptions method
[window addSubview:[viewController view]];
[self.window makeKeyAndVisible];
[self initGlobals];
return YES;
}
Теперь в вашем классе UIViewController нам нужно сделатьэтот класс соответствует протоколу UIAlertView.Мы собираемся использовать один из методов делегата, который сообщает нам, когда нажимается кнопка в UIAlertView.
@interface MyViewController : UIViewController <UIAlertViewDelegate>
{
...
}
В нашем файле реализации (файл MyViewController.m) мы проверяем значение, хранящееся в текстовом файле.перед отображением UIAlertView.
#import "MediaDirectory.h"
#import <Foundation/NSFileManager.h>
#import <Foundation/NSFileHandle.h>
-(void)viewDidLoad
{
...
BOOL shouldShowAlert = false;
NSString *fileStatus = nil;
// check if the file exists in the Documents directory and read its value
// if it does. If the value read from file is "show again",
// we bring up a UIAlertView
if([[NSFileManager defaultManager] fileExistsAtPath:[MediaDirectory mediaPathForFileName:@"fileStatus.txt"]] == YES)
{
fileStatus = [[NSMutableString alloc] initWithContentsOfFile:[MediaDirectory mediaPathForFileName:@"fileStatus.txt"]
encoding:NSUTF8StringEncoding
error:nil];
if([fileStatus isEqualToString:@"show again"] == YES)
{
shouldShowAlert = true;
}
else if([fileStatus isEqualToString:@"don't show again"] == YES)
{
shouldShowAlert = false;
}
}
if(shouldShowAlert == true)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"My Alert View Title"
message:@"my message"
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:@"Don't Show Again", nil];
// we set a tag for this UIAlertView to distinguish between this UIAlertView
// and other UIAlertView in case there are any.
// I use a value of 10, you can use any value but make sure it is unique
[alert setTag:10];
[alert show];
[alert release];
}
}
Теперь перейдем к последней части, где мы обрабатываем, какую кнопку пользователь нажал для UIAlertView.
Где-то в файле MyViewController.m, напишите этоМетод делегата:
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
// making sure its the UIAlertView we want
if([alertView tag] == 10)
{
// By default, the "cancel" button has an index of 0
// and the next button would have a index of 1
// In our case, we set the first button is "OK"
// and "Don't Show Again" as second button
if(buttonIndex == 1)
{
NSString *fileStatus = [[NSString alloc] initWithString:@"don't show again"];
[fileStatus writeToFile:[MediaDirectory mediaPathForFileName:@"fileStatus.txt"]
atomically:YES
encoding:NSUTF8StringEncoding
error:nil];
[fileStatus release];
}
}
}
Надеюсь, я ничего не пропустил, дайте мне знать, работает ли он или нет.