PHAdjustmentData is nil in "startContentEditingWithInput" - ios

I'm working on a photo-editing extension app, and I want it to be able to save the information about the changes made into the PHAdjustmentData, so that user can modify those changes later. I save all the required data into PHAdjustmentData, however, next time I edit the image - PHAdjustmentData is nil.
Here is a sample code:
#property (strong, nonatomic) PHContentEditingOutput *output;
- (void)startContentEditingWithInput:(PHContentEditingInput *)contentEditingInput placeholderImage:(UIImage *)placeholderImage
{
self.output = [[PHContentEditingOutput alloc] initWithContentEditingInput:contentEditingInput];
// here contentEditingInput.adjustmentData is always nil
}
- (void)finishContentEditingWithCompletionHandler:(void (^)(PHContentEditingOutput *))completionHandler
{
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:#"value1" forKey:#"key1"];
[dict setObject:#"value2" forKey:#"key2"];
NSData *adjData = [NSKeyedArchiver archivedDataWithRootObject:dict];
PHAdjustmentData *phAdjData = [[PHAdjustmentData alloc] initWithFormatIdentifier:#"ident" formatVersion:#"1.0" data:adjData];
self.output.adjustmentData = phAdjData;
NSData *data = UIImageJPEGRepresentation(result, 1.0);
[data writeToURL:self.output.renderedContentURL options:NSDataWritingAtomic error:nil];
completionHandler(self.output);
}
How do I save the adjustment data properly, so that I can access it next time user edits the image? Thanks!

PhotoKit gives you adjustment data in startContentEditingWithInput only if you've agreed to handle that data. You agree by implementing canHandleAdjustmentData to check the format identifier and version of the adjustment and then return true for formats you can handle.
If you return false from canHandleAdjustmentData, then you'll get a nil adjustment data in startContentEditingWithInput. Not only that, you'll also get a pre-edited version of the photo image, so you can't work off of how it looked before the last edit.

Related

Appending data to a string without losing previous data

I have this is on the top of my program:
#property (strong, nonatomic) NSMutableData *data;
I thought this would allow me to store the value from every time this method runs:
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests
{
for (CBATTRequest *request in requests) {
NSString *stringValue = [[NSString alloc] initWithData: [request value] encoding:NSUTF8StringEncoding];
// Have we got everything we need?
if ([stringValue isEqualToString:#"EOM"]) {
// We have, so show the data,
[self.textview setText:[[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding]];
}
// Otherwise, just add the data on to what we already have
[self.data appendData:[request value]];
}
}
This method waits for a write request to be received and stores the value in a string. I have a core bluetooth central that is sending three blocks of data. This is to get around the data transfer size restriction within bluetooth LE. The problem is I can't get the three values stored. I am trying to not just store the last value but add the new value to the end of a nsstring or nssdata every time the method is called. Any help would be greatly appreciated. I thought the property at the top would allow me to do it but it either only stores the last value or nothing at all. I am not used to the ways of objective c yet. Thanks.
Even this doesn't write anything to self.data:
NSString * result = [[requests valueForKey:#"value"] componentsJoinedByString:#""];
NSData* data = [result dataUsingEncoding:NSUTF8StringEncoding];
[self.data appendData:data];
// Log it
NSLog(#"%#",self.data);
You should use NSMutableArray instead of NSString as a mutable string.
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests
{
NSMutableString *stringValue = [[NSMutableString alloc] init];
for (CBATTRequest *request in requests) {
[stringValue appendString:[[NSString alloc] initWithData:[request value] encoding:NSUTF8StringEncoding]];
// Have we got everything we need?
if ([stringValue isEqualToString:#"EOM"]) {
// We have, so show the data,
[self.textview setText:[[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding]];
}
// Otherwise, just add the data on to what we already have
[self.data appendData:[request value]];
}
Remember kids when dealing with NSMutableData always initialize it!
_data = [[NSMutableData alloc] init];
This fixed the null problem for me.

NSMutableDictionary data not saving in file for wrong file directory

I have two UITextField
email
password
These two field values are stored in a NSMutableDictionary call userData. Now i want to save these two field values in a file, so that the records keep there and i can restore this record to check user login correctly. Here i want to accomplish that, but not working.
My code :
-(void) saveRegistrationData
{
userData = [[NSMutableDictionary alloc]
initWithObjects:[[NSMutableArray alloc] initWithObjects:#"123456", nil]
forKeys:[[NSMutableArray alloc] initWithObjects:#"admin#gmail.com", nil]];
[userData setObject:passwordTextField.text forKey:emailTextField.text];
NSString *savePath = [#"/MediaFiles/Documents/" stringByExpandingTildeInPath];
[userData writeToFile: savePath atomically: YES];
//[userData writeToFile:#"MediaFiles/Documents/" atomically:YES];
for (id key in userData)
{
NSLog(#"%# is for %#", key, [userData objectForKey:key]);
}
}
I think the path is not setting correctly. If any one similar with the solution, please share with me. Thanks in advanced. Have a good day.
It's not working for a few reasons.
1) You're writing to a folder in the root of the device's filesystem. Apple uses sandboxing to prevent this from happening as you could overwrite and modify any system files.
2) You're writing to a folder rather than a file. To write to a file, you need to specify a filename (and extension). i.e. "/MediaFiles/Documents/dnt_lk_at_dis.plist"
In order to fix these issues, you need to be firstly getting the path to the sandbox (documents directory) and then append the filepath.
NSString *docsPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filename = #"secret.plist";
NSString *filePath = [docsPath stringByAppendingPathComponent:filename];
Furthermore, I strongly suggest that you instead use the keychain for storing sensitive user information. Anybody with a jailbroken device, or anybody that has access to the file system will be able to extract the user's information if it is stored in plain-text. At the very least, please encrypt the password before writing it to disk.
-(void) saveRegistrationData
{
userData = [[NSMutableDictionary alloc] init];
[userData setObject:passwordTextField.text forKey:#"password"];
[userData setObject:emailTextField.text forKey:#"email"];
// Alternative to the above:
userData = [[NSMutableDictionary alloc]
initWithObjects:[[NSMutableArray alloc] initWithObjects:passwordTextField.text, emailTextField.text, nil]
forKeys:[[NSMutableArray alloc] initWithObjects:#"password", #"email" nil]];
NSString *savePath = [#"/MediaFiles/Documents/myDict.plist" stringByExpandingTildeInPath]; // write to a file, not a dictionary
[userData writeToFile: savePath atomically: YES];
for (id key in userData)
{
NSLog(#"%# is for %#", key, [userData objectForKey:key]); // now you should see the result that you want to.
}
// Alternative for the above - the lazy way of doing it:
NSLog (#"theDictionary: %#", userData);
}
Please forgive me any typos or so. I did not compile it for you :-)

Iterating an NSMutableDictionary with UIImage not working

I am trying to add Images fetched from an external service to an NSMutableDictionary and seeing weird results. This is what I am doing:
- (void)fetchImages{
//Fetch Item Brand Images
//self.itemBrands is an NSArray of NSDictionaries
for (NSDictionary *itemBrand in self.itemBrands){
NSString *currentItemId = [itemBrand objectForKey:#"ITEM_ID"];
//Valid Item Id. This Log message is displayed
NSLog(#"Current Item Id: %#",currentItemId);
NSString *currentItemImageUrl = [[IMAGE_URL stringByAppendingString:currentItemId] stringByAppendingString:#".png"];
//Image URL is valid. This log message is displayed
NSLog(#"Current Image URL: %#",currentItemImageUrl);
NSURL *url = [NSURL URLWithString:currentItemImageUrl];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
if (image == nil){
//This log message is displayed when image is not present
NSLog(#"Image not Present 1");
}else{
//This log message is displayed when image is present
NSLog(#"Image Present 1");
[self.itemBrandImages setObject:image forKey:currentItemId];
}
}
//This for loop is not being executed at all. No log messages displayed.
for(id key in self.itemBrandImages){
NSLog(#"Current Item Id2: %#",key);
if ([self.itemBrandImages objectForKey:key] == nil){
NSLog(#"Image Not Present 2");
}else{
NSLog(#"Image Present 2");
}
}
}
The 2nd for loop where I am iterating over self.itemBrandImages is not being executed at all. None of the log messages inside are being displayed.
I tried the following before posting my issue here:
1) Researched similar problems in stack overflow and incorporated suggestion from one of them. The suggestion was "Perform an alloc init of the NSMUtableDictionary" in the init method of the .m file. This didn't help either.
2) To isolate the issue, I even tried adding a simple string to the NSMUtableDictionary instead of the image but even that does not seem to retained.
I am really confused as as to what I am missing or doing wrong here. Inputs are really appreciated.
Thanks,
Mike G
Perhaps:
for(NSString *key in [self.itemBrandImages allKeys])
I did an alloc init of the NSMutableDictianary right in my fetchImages method and it worked! Not sure why the alloc init in the init method did not work.
So here are my takeaways from this issue:
1) If you have an Array or dictionary #property that you are just getting and setting and not really adding or deleting objects to, then you don't need to explicitly alloc init them.
2) If you have an Array or dictionary #property that you are adding or deleting objects to ,you need to explicitly alloc init them.
Are my above statements true? Would love to hear your inputs on this.
Thanks,
Mike
New code:
- (void)fetchImages{
//Fetch Item Brand Images
self.itemBrandImages = [[NSMutableDictionary alloc] init];
for (NSDictionary *itemBrand in self.itemBrands){
NSString *currentItemId = [itemBrand objectForKey:#"ITEM_ID"];
NSLog(#"Current Item Id in ItemList: %#",currentItemId);
NSString *currentItemImageUrl = [[#"http://anythingtogo.freeiz.com/images/"stringByAppendingString:currentItemId] stringByAppendingString:#".png"];
NSLog(#"Current Image URL in ItemList: %#",currentItemImageUrl);
NSURL *url = [NSURL URLWithString:currentItemImageUrl];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
if (image == nil){
NSLog(#"Image not Present 1");
}else{
NSLog(#"Image Present 1");
[self.itemBrandImages setObject:#"Test" forKey:currentItemId];
}
}

Saving Array easy way

I have used NSuserDefaults and NSkeyedArchive before but i dont think it will work for my new project..
I get data back from JSON and store it in an array (name,age,country) (all NSString)
i want to make a save button in the detail view so that it saves that person's data.
And show the saved data in another tableview. (for loop on the array and get all objects back)
How should i handle this in a easy way.. i except max 40 stored names so its not so heavy..
So in short i want a function like you see in "home app's" where you can "favorite/store a house"
-- Update
viewDidLoad
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [docDir stringByAppendingPathComponent:#"Names.plist"];
NSMutableArray *array = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
arrayWithNames = [[NSMutableArray alloc]init];
[arrayWithNames addObjectsFromArray:array];
Savebutton
NSMutableArray *nameInfo = [[NSMutableArray alloc]initWithObjects:self.name,self.age,self.country, nil];
[arrayWithNames addObjectsFromArray:nameInfo];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Names.plist"];
[arrayWithNames writeToFile:path atomically:YES];
This works but i get all data together instead of every array as an independent object
btw i made sure there cant be a NULL :)
As long as all of the data is NSString values, as you say, you can just use writeToFile:atomically: to save an array to a file. However, JSON sometimes contains nulls, which aren't compatible with that method. If you try to use that method when nulls are present, it will throw an exception. If there's any chance of nulls (and there almost always is a chance), you'll need to take some precautions. A couple of possibilities:
Make mutable copies of your data, run through it, and remove nulls or replace them with something else (like an empty string).
Convert the data back to JSON via [NSJSONSerialization dataWithJSONObject:options:error:] and then write the resulting NSData to a file.
I not quite understand your question.
But in your case what I did was create a Model with the structure of information I intended to store (in your case looked Person) and created an array in which i will add the objects Person
Could use several cases to save, but in my opinion, the simplest would be through the NSUserDefaults (the solution depends heavily on your database).
Soo, you will have the model Person
import <Foundation/Foundation.h>
#interface Person : NSObject
#property(nonatomic,strong) NSString *name;
#property(nonatomic,strong) NSString *country;
#property(nonatomic,strong) NSString *age;
...
With the methods for the encryption:
- (void)encodeWithCoder:(NSCoder *)encoder {
//Encode properties, other class variables, etc
[encoder encodeObject:self.name forKey:#"name"];
[encoder encodeObject:self.age forKey:#"age"];
[encoder encodeObject:self.country forKey:#"country"];
}
- (id)initWithCoder:(NSCoder *)decoder {
if((self = [super init])) {
//decode properties, other class vars
self.name = [decoder decodeObjectForKey:#"name "];
self.age = [decoder decodeObjectForKey:#"age"];
self.country = [decoder decodeObjectForKey:#"country"];
}
return self;
}
Then you create a NSMutableArray where you add your objects.
[arrayPeople addObject:person];
When you decide to store in your application data you can do this:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *myEncodedObjectShopping = [NSKeyedArchiver archivedDataWithRootObject:arrayPeople];
[defaults setObject:myEncodedObjectShopping forKey:#"people"];
To retrive the data:
NSData *myDecodedObject = [defaults objectForKey:#"people"];
NSMutableArray *decodedArray =[NSKeyedUnarchiver unarchiveObjectWithData: myDecodedObject];

Write JSON from textfields to a file for iOS 5+

I'm new to iOS programming, and having trouble finding a beginner-level explanation of how to write the contents of multiple text fields to a local json file in such a way to keep everything organized.
For example, a user form would have Name, Address, Email, etc., which would need to be put into a Customer object.
The purpose of this is to save data from several forms, and eventually pass that data to a database.
You'll need to convert your text fields into a dictionary (or dictionary of dictionaries). Once you have that done, you convert the dictionary into JSON data and save that:
NSError *error = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:myJSONDict options:0 error:&error];
if (jsonData != nil) {
NSString *jsonFilePath = ...;
BOOL status = [jsonData writeToFile:jsonFilePath atomically:YES];
if (!status) {
NSLog(#"Oh no!");
}
} else {
NSLog(#"My JSON wasn't valid: %#", error);
}
You just need to create the path and check the status.
NSMutableDictionary* dict = [NSMutableDictionary dictionary];
[dict setObject:form.name.text forKey:#"name"]'
[dict setObject:form.address.text forKey:#"address"];
...
NSString* jsonString = [yourFavoriteJsonTool convertToJson:dict];

Resources