iOS Keyboard Extension(App Groups) - ios

i have a question about Keyboard Extension.
Container app has many images.(ex > 100 images and total 100MB)
and container app has saved using NSUserDefaults.
like this:
NSMutableArray* arr = [NSMutableArray new];
for(NSInteger i = 0; i < 100; i++)
{
UIImage* img = [UIImage imageNamed:[NSString stringWithFormat:#"img%ld",i]];
NSData* data = UIImagePNGRepresentation(image);
[arr addObject:data]
}
NSUserDefaults* ud = [[NSUserDefaults alloc] initWithSuiteName:#"<group identifier>"];
[ud setObject:arr forKey:#"image_data"];
[ud synchronize];
and keyboard app gets image data from NSUserDefaults.
Is it right way that container app send heavy size data to keyboard app?
In special case, when NSUserDefaults instance accesses method(objectForKey:) in keyboard app, keyboard app crashed.
The special case is :
if image data size in NSUserDefaults is bigger than about 30MB(not sure), keyboard app crashed and if the size is smaller than about 30MB, it works well.
Is there max size limit of NSUserDefaults?
i just want like this app.
i want to know that i control heavy size data in keyboard app.

1) First you have to write image in Shared document directory.
- (NSString *)getSharedLocationPath:(NSString *)appGroupName {
NSURL *groupContainerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:#"group.yourGroupName"];
return [groupContainerURL relativePath];
}
2) Write Image to above shared Directory.
NSString *path = [[self getSharedLocationPath:#"group.yourGroupName"] stringByAppendingPathComponent:[NSString stringWithFormat:#"%#",images]];
//Here fileData is your Image data.
[fileData writeToFile:path atomically:YES];
3) Exactly get this path to Keyboard Extension class same as above.
- (NSString *)getSharedLocationPath:(NSString *)appGroupName {
NSURL *groupContainerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:#"group.yourGroupName"];
return [groupContainerURL relativePath];
}
//Here get content of directory from shared document directory.
NSArray *directoryContent = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[self getSharedLocationPath:#"group.yourGroupName"] error:NULL];
for (Count = 0; Count < (int)[directoryContent count]; Count++)
{
NSLog(#"File %d: %#", (Count + 1), [directoryContent objectAtIndex:Count]);
}
//Now you get your images from app shared directory.

Related

Get file name of copied document off UIPasteBoard

I am trying to add a feature to an existing iOS app so that documents "copied" within Mail (say a PDF) can be pasted into my app.
After a PDF document is viewed in Mail and "Copy" chosen from the Action menu, within my app's code, when I inspect:
[[UIPasteboard generalPasteboard] items]
I can see the document as per:
{
"com.adobe.pdf" = {length = 875113, bytes = 0x25504446 2d312e35 0d0a25b5 b5b5b50d ... 300d0a25 25454f46 };
}
)
And further retrieve it via:
po [[UIPasteboard generalPasteboard] valueForPasteboardType:#"com.adobe.pdf"]
<OS_dispatch_data: data[0x2820e5c00] = { leaf, size = 875113, buf = 0x1125e0000 }>
However, is there any way to get the document's name? In the Files.app when I paste the same document it gets pasted as the original file name.
Should I be using the pasteboard for this, or if there another API which can get access to the copied document with the file name?
Even if this question is a little older I happened to search for the same and finally found the solution. So for future reference:
Starting with iOS 11 UIPasteboard contains an array itemProviders which gives you all the information about the objects that are available. The same is used for Drag/Drop.
So with the following logic you can save the items to a certain path:
NSArray *items = [[UIPasteboard generalPasteboard] itemProviders];
for (NSInteger i = 0; i < itemProvider.count; i++) {
NSItemProvider *itemProvider = itemProvider[i];
NSString *identifier = itemProvider.registeredTypeIdentifiers[0];
[itemProvider loadDataRepresentationForTypeIdentifier:identifier completionHandler:^(NSData * _Nullable data, NSError * _Nullable error) {
NSMutableDictionary *result;
if (!error) {
NSString *ext = (__bridge NSString *)(UTTypeCopyPreferredTagWithClass((__bridge CFStringRef _Nonnull)(identifier), kUTTagClassFilenameExtension));
if ([ext isEqualToString:#"jpeg"]) {
ext = #"jpg";
}
NSString *mime = (__bridge NSString *)(UTTypeCopyPreferredTagWithClass((__bridge CFStringRef _Nonnull)(identifier), kUTTagClassMIMEType));
if (!mime) {
mime = #"application/*";
}
NSString *filename = itemProvider.suggestedName;
NSString *path = [folderPath stringByAppendingPathComponent:filename];
[data writeToFile:path options:NSDataWritingAtomic error:&error];
}
}
}

Looking for a Logic Solution to Build Dynamic Filepath in iOS

I have a file structure which is being built in the following manner.
1) Each user is provided an ID in MySQL database.
2) When user uploads an image from iphone the image is placed in the following directory:
`../images/[USER_ID]/[IMAGE_NUMBER].jpg`
3) In the path noted above, [IMAGE_NUMBER] is generated based upon the submission value. So the first image uploaded will be titled 1.jpg, the second as 2.jpg etc…
So to build a sample directory for the purposes of this question the structure could look something like this:
../images-->
../10/1.jpg
../10/2.jpg
../10/3.jpg
../11/4.jpg
../11/5.jpg
../10/6.jpg
../11/7.jpg
So in this case, User #10 uploaded 3 images, then logged out. Along comes User #11 and she uploads 2 images before logging out. And finally, User #10 logs back in and uploads another image.
Okay now that we have the summary of out the directories are being generated and images are dynamically input, let me get to the ultimate question. I would like to be able to display thumbnails of all the images on a view in the iphone when a user clicks a button that we will call btnRefresh
Here is the method that is associated with btnRefresh:
-(IBAction)btnRefreshTapped
{
[self refreshStream];
}
-(void)refreshStream {
[[API sharedInstance] commandWithParams:[NSMutableDictionary dictionaryWithObjectsAndKeys:
#"stream",#"command",
nil]
onCompletion:^(NSDictionary *json) {
[self showStream:[json objectForKey:#"result"]];
}];
}
As you can see this is referencing the API sharedInstance here is that method:
+(API*)sharedInstance
{
static API *sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
sharedInstance = [[self alloc] initWithBaseURL:[NSURL URLWithString:kAPIHost]];
});
return sharedInstance;
}
and finally we come full circle to the URLWithString value:
-(NSURL*)urlForImageWithId:(NSNumber*)IdPhoto isThumb:(BOOL)isThumb {
int IdValue = [[user objectForKey:#"id"] intValue];
NSString* urlString = [NSString stringWithFormat:#"%#/%#upload/%d/%#%#.jpg",
kAPIHost, kAPIPath, IdValue, IdPhoto, (isThumb)?#"-thumb":#""
];
return [NSURL URLWithString:urlString];
}
So, herein lies my problem. As this is currently being defined I can only see the images of the user that is logged into the app when they click btnRefresh. The other image locations show up as greyed out images due to the broken URLs. So, how can I redefine IdValue to cycle through available folders and pull the associated images for display?
I know this is a complex problem so thank you to putting some brainpower into a solution.
I don't know is it what you asking but you can get all files from the directory via this code:
NSArray *contents = [fileManager contentsOfDirectoryAtURL:YourURL
includingPropertiesForKeys:#[] // <-Add key/s if needed
options:NSDirectoryEnumerationSkipsHiddenFiles error:nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"pathExtension == 'jpg'"];
for (NSURL *fileURL in [contents filteredArrayUsingPredicate:predicate])
{
// Enumerate each .jpg file in directory
}
You can specify images directory and you should be able to find the images and get url to that.
The other way is recursively enumerate files in directory, it's more powerful and it can be amended to your requirement:
NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtURL:YOURURL
includingPropertiesForKeys:#[NSURLNameKey, NSURLIsDirectoryKey] // <-Add more key if needed
options:NSDirectoryEnumerationSkipsHiddenFiles
errorHandler:^BOOL(NSURL *url, NSError *error)
{
NSLog(#"Error %#", error);
}];
NSMutableArray *mutableFileURLs = [NSMutableArray array];
for (NSURL *fileURL in enumerator) {
NSString *filename;
[fileURL getResourceValue:&filename forKey:NSURLNameKey error:nil];
NSNumber *isDirectory;
[fileURL getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil];
if (![isDirectory boolValue]) {
[mutableFileURLs addObject:fileURL];
}
}
Hope one of those will be usefull for you.
Modifying what Greg just answered so that you don't have to iterate the array.
NSArray *paths = [fileManager contentsOfDirectoryAtURL:YourURL
includingPropertiesForKeys:#[]
options:NSDirectoryEnumerationSkipsHiddenFiles error:nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:
[NSString stringWithFormat:
#"self ENDSWITH '/filename.jpg'"]];
NSArray *filteredArray = [paths filteredArrayUsingPredicate:predicate];
if ([newarray lastObject]) {
//you have your path here
}
filename.jpg is the IdPhoto.jpg in your code. This code with work because of the type of data you have. I have included "/" in filename.jpg so that there are no issues in detecting 110.jpg vs 10.jpg.

how to store an image path in a plist?

I know this is probably a silly question but I'm storing most of my game data in a plist - with that I'd like to include references to images used within my game - same hierarchal level as 'supporting files'. I have different types of images stored in 3 separate folders. One folder for example is called imageclue. How could I store the path in my plist, I'm stuck because I can't just store the path in my plist as string - filename.jpg. I've tried getting the path of the file but when I log it out it .
Sorry if I'm not explaining well and thank you in advance for any help :)
EDIT**
I have a plist file added to my program I don't want to programatically add to it as the images are constants - the screenshots below show a tutorial instead of the filename.jpg (because that won't work seen as my images are stored in a file) I wondered what path name do I use as a string.
The image is from a tutorial off of appcoda.com - where it says thumbnails are the image path files. If you look at where the images are stored on the left - they are stored with the program files. My images are in a folder in there so I'm confused as to what to enter in my plist for the image file.
Hope this clears up what I meant, sorry :)
Store three variables in .h file
#interface YourViewController : UIViewController
{
NSString *folder1;
NSString *folder2;
NSString *folder3;
}
in viewdidload:
-(void) viewdidLoad
{
//get the documents directory:
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
//getting the folder name:
folder1 = [NSString stringWithFormat:#"%#/imageclue",
documentsDirectory];
folder2 = [NSString stringWithFormat:#"%#/folder2",
documentsDirectory];
folder3 = [NSString stringWithFormat:#"%#/folder3",
documentsDirectory];
}
-(NSArray*) getPlistFromFolder:(NSString*)folder imageName:(NSString*)image
{
NSString *imageTitle = [NSString stringWithFormat:#"%#/image",
folder];
NSArray *data = [[NSArray alloc] initWithContentsOfFile:plistName];
return data;
}
So in the plist file, just store the image name.
Hope this helps...
Do it like this,
NSDictionary *imagePaths = #{#"image 1": [NSHomeDirectory() stringByAppendingPathComponent:#"image 1"]};
[self writeToPlist:imagePaths];
- (void)writeToPlist:imagePaths:(id)plist{
NSError *error;
NSData *data = [NSPropertyListSerialization dataWithPropertyList:plist format:kCFPropertyListXMLFormat_v1_0 options:0 error:&error];
if(error){
NSLog(#"Could not write to file");
return;
}
[data writeToFile:[self plistPath] atomically:YES];
}
Like wise loading is simple as this;
[self loadImagePathForImageNamed:#"image 1"];
- (NSString*)loadImagePathForImageNamed:(NSString*)imageName{
}
- (NSString*)loadImagePathForImageNamed:(NSString*)imageName{
NSData *data = [NSData dataWithContentsOfFile:[self plistPath]];
NSString *error;
NSPropertyListFormat format;
NSDictionary *dictionary = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&error];
if(error){
NSLog(#"Could not open plist %#", error);
return nil;
}
return dictionary[imageName];
}
You may have to handle the error when the file is not there by creating a new one, otherwise this should work.
You are storing path right way, just need to store filename of image with extension in plist when your images are in your Application Bundle, for more reference you can define key name Instead "item1", "item2" in your plist.
Now coming to actual Question, how to access image from plist
Step 1 : Read your recipes.plist from Application Bundle
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:#"recipes" ofType:#"plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:bundlePath];
Step 2 : Now Get Image/Thumbnails name out of it, which you want to load
Step 3 : Define following Function in your Controller, which returns image from name
- (UIImage *)getImageWithName:(NSString *)imageFileName
{
NSString *ext = [imageFileName pathExtension];
NSString *imagePath = [[NSBundle mainBundle] pathForResource:[imageFileName stringByDeletingPathExtension] ofType:ext];
return [UIImage imageWithContentsOfFile:imagePath];
}
HOW TO USE
Suppose you want to load Image with key "Item2" then write following code
NSString *imageFileName = [[dict objectForKey:#"Thumbnail"] valueForKey:#"Item2"];
UIImage *item2Image = [self getImageWithName:imageFileName];
For "Item6"
NSString *imageFileName1 = [[dict objectForKey:#"Thumbnail"] valueForKey:#"Item6"];
UIImage *item6Image = [self getImageWithName:imageFileName1];

iOS - Can't Display Downloaded Image

I am downloaded images using the below code, but whenever I try to display them nothing shows up. I have tested the downloading of the images to my desktop from the app (in simulator) and all the images are created just fine. So I know they are being saved into the App's Documents directory.
Any ideas on what I am doing wrong?
Download Image Code:
-(void)saveThumbnails:(NSMutableArray *)thumbnails{
for(NSNumber *videoID in thumbnails){
// Get an image from the URL below
NSURL *thumbnailURL = [self generateThumbnailURL:[videoID intValue]];
UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:thumbnailURL]];
NSLog(#"%f,%f",image.size.width,image.size.height);
// Let's save the file into Document folder.
// You can also change this to your desktop for testing. (e.g. /Users/kiichi/Desktop/)
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);//Find Application's Document Directory
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:#"DownloadedThumbnails"];
// NSString *dataPath = #"/Users/macminidemo/Desktop/gt";//DEBUG SAVING IMAGE BY SAVING TO DESKTOP FOLDER
//Check if Sub-directory exists, if not, try to create it
if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath]){
NSError* error;
if([[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:NO attributes:nil error:&error]){
NSLog(#"New Folder Created!");
}
else
{
NSLog(#"[%#] ERROR: attempting to write create new directory", [self class]);
NSAssert( FALSE, #"Failed to create directory maybe out of disk space?");
}
}
NSArray *splitFilename = [[self generateThumbnailFilename:[videoID intValue]] componentsSeparatedByString:#"."];//Break Filename Extension Off (not always PNGs)
NSString *subString = [splitFilename objectAtIndex:0];
NSString *formattedFilename = [NSString stringWithFormat:#"%#~ipad.png",subString];
NSString *localFilePath = [dataPath stringByAppendingPathComponent:formattedFilename];
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(image)];
[imageData writeToFile:localFilePath atomically:YES];
NSLog(#"Image: %# Saved!",formattedFilename);
}
}
Display Image Code:
if(currentVideo.thumbnail!=(id)[NSNull null] || ![currentVideo.thumbnail isEqualToString:#"missing_image.png"]){
NSArray *splitFilename = [currentVideo.thumbnail componentsSeparatedByString:#"."];//Break Filename Extension Off (not always PNGs)
NSString *subString = [splitFilename objectAtIndex:0];
NSString *formattedFilename = [NSString stringWithFormat:#"%#~ipad.png",subString];
UIImage *thumbnailImage = [UIImage imageNamed:formattedFilename];
NSLog(#"Image Name: %#",formattedFilename);
[videoThumbnail setImage:thumbnailImage];
[buttonVideo addSubview:videoThumbnail];
}else{
UIImage *thumbnailImage = [UIImage imageNamed:#"video-details-thumbnail"];
[videoThumbnail setImage:thumbnailImage];
[buttonVideo addSubview:videoThumbnail];
}
*And there are no issues displaying the buttonVideo or anything like that. I have tested just setting a test image and that one display just fine (i.e. the "else" statement when run individually works just fine using the default thumbnail)
The documentation for imageNamed says that it works with files that are in the app's main bundle. This suggests to me that it's only appropriate for images that are supplied as in-app resources. Try imageWithContentsOfFile: to get at the content of the documents directory.

What is the correct way to save user data using NSFileManager?

I am having trouble initializing dictionaries I use throughout my program to store user achievements and scores.
I have almost identical code for the two dictionaries and only the gameCenterData dictionary seems to be working properly. I have tried altering the plist file name and contents yet nothing seems to make the playerData dictionary properly load info from the file as it should
In the Root View Controller I have the following code (playerData and gameCenterData are both NSMutableDictionaries and the plist files are in the proper place)
-(NSString *)scoreFilePath
{
NSArray *scorePath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [scorePath objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:#"PlayerScoreData.plist"];
}
-(NSString *)gameCenterFilePath
{
NSArray *gameCenterPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [gameCenterPath objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:#"GameCenterData.plist"];
}
then the view did load
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *playerDataPath = [self scoreFilePath];
if (! [[NSFileManager defaultManager] fileExistsAtPath:playerDataPath])
{
playerData = [NSMutableDictionary dictionaryWithContentsOfFile:[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:#"scoreData.plist"]];
[playerData writeToFile:[self scoreFilePath] atomically:YES];
NSLog(#"Player data file does not exist");
}
else
{
playerData = [[NSMutableDictionary alloc] initWithContentsOfFile:[self scoreFilePath]];
NSLog(#"player data file exists");
}
NSLog(#"scoreData is %#",playerData);
NSString *gameCenterPath = [self gameCenterFilePath];
if (! [[NSFileManager defaultManager] fileExistsAtPath:gameCenterPath])
{
gameCenterData = [NSMutableDictionary dictionaryWithContentsOfFile:[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:#"gameCenterData.plist"]];
[gameCenterData writeToFile:[self gameCenterFilePath] atomically:YES];
NSLog(#"game center data file does not exist");
}
else
{
gameCenterData = [[NSMutableDictionary alloc] initWithContentsOfFile:[self gameCenterFilePath]];
NSLog(#"game center data file exists");
}
NSLog(#"gameCenterData is %#",gameCenterData);
the output is as follows
2012-08-05 11:46:49.991 GlobeRoller[6410:1be03] Player data file does not exist
2012-08-05 11:46:49.992 GlobeRoller[6410:1be03] playerData is (null)
2012-08-05 11:46:50.061 GlobeRoller[6410:1be03] game center data file does not exist
2012-08-05 11:46:50.062 GlobeRoller[6410:1be03] gameCenterData is {
"Career Odometer" = 0;
"Career Score" = 0;
"Cities Found" = 0;
"Offline Games Played" = 0;
"Online Games Played" = 0;
"Online Games Won" = 0;
}
I have searched all of the questions and answers to see if I can find out why this isn't working for both methods. Any help you could offer, or resources you could point me to I would greatly appreciate.
Thank you,
CF
The plist file you are trying to load from the bundle is either not there, or has been created improperly. Directly from the documentation of dictionaryWithContentsOfFile:.
Return Value
A new dictionary that contains the dictionary at path, or
nil if there is a file error or if the contents of the file are an
invalid representation of a dictionary.
You should make sure you are using the proper file name, and then open your plist in Xcode to see if it is properly formatted.
iOS is case sensitive. Are you sure that your file in the bundle is lower case, i.e. "#"scoreData.plist", and not upper case like the name your code uses? Also, verify that these two files are in your bundle - check the build phase or select the files (one at a time) and look in the 3rd Xcode pane in the file attribute section (to verify they are included in your target). If all that looks good then when you try to retrieve the files from your bundle:
Also, don't try to find the file at the root level of the bundle - you should be using:
NSString *path = [[NSBundle mainBundle] pathForResource:#"GameCenterData" ofType:#"plist"];
NSLog(#"PATH is %#", path);
...then use path instead of the code you are using now

Resources