Set attribute to managed object - ios

I'm fairly new to ios development and I'm trying to set some imagedata as an attribute of a mangedobject I've created.
I've read, and re-read the apple docs and can't seem to find what I'm looking for. I know it must be something simple I'm missing but I can't put my finger on it.
If anyone could point me in the right direction i would really appreciate it!
here's my current code:
-IBAction saveSignature: (id) Sender {
NSData *imageData = UIImagePNGRepresentation(mySignature.image);
NSManagedObject *pilotSignature = [[NSEntityDescription
insertnewObjectForEntityForName:#"pilotsignature"
inManagedObjectContext: selfmanagedObjectContext]]

Related

NSData Assignment Vanishes (becomes nil) Directly After Assigned

Let me start by saying I'm not proficient in objective c, nor am I an iOS developer. I'm working on a react-native app and find that I'm having to dig into the native code. So, I appreciate your patience with me and would also very much appreciate if you made zero assumptions about what I might, or might not know. Thx!
I'm trying to use react-native-mail but it fails to attach the photo I've selected to the email.
In troubleshooting, I jumped into Xcode's debugger for the first time. Stepping through the code, it appears as though the attachmentPath which is something like file:///var/mobile/... is being assigned to the variable fileData as type NSData. But then, taking one step further into the code it becomes nil.
I'm not sure why this would happen nor how to go about troubleshooting this. Here's an image of the debugger session with 3 screenshots stitched together side-by-side.
Here's the code: RNMail.m
All pointers, tips, guidance, and advice welcome
In your first screenshot, the debugger is still on the line that declares and assigns the fileData variable. This means that that line hasn't actually been executed yet. -dataWithContentsOfFile: hasn't yet been called, and thus the value that appears to be in fileData is not meaningful; what you're seeing is just garbage data prior to the variable actually being assigned. In your second screenshot, the -dataWithContentsOfFile: method has finished running, and it has returned nil. What you need to do is to figure out why you're getting nil from -dataWithContentsOfFile:. Perhaps the path to the file is incorrect, or perhaps you don't have permission to read it, or perhaps you have a sandboxing issue.
I would suggest using -dataWithContentsOfURL:options:error: instead of -dataWithContentsOfFile:. This will return an error by reference (create an NSError variable ahead of time, assign it to nil, pass a pointer to the error as the third parameter to -dataWithContentsOfURL:options:error:, and then check the error if the method returns nil). More likely than not, the contents of the error will explain what went wrong when trying to read the file.
EDIT: Looking at your screenshot again, the problem is clear; from the description of the contents of attachmentPath, we can see that it isn't a path at all, but instead it contains a URL string (with scheme file:). So you cannot pass it to the APIs that use paths. This is okay, since the URL-based mechanisms are what Apple recommends using anyway. So, just turn it into a URL by passing the string to -[NSURL URLWithString:] (or, even better, -[[NSURLComponents componentsWithString:] URL], since it conforms to a newer RFC). So, something like:
// Get the URL string, which is *not* a path
NSString *attachmentURLString = [RCTConvert NSString:options[#"attachment"][#"path"]];
// Create a URL from the string
NSURL *attachmentURL = [[NSURLComponents componentsWithString:attachmentURLString] URL];
...
// Initialize a nil NSError
NSError *error = nil;
// Pass a pointer to the error
NSData *fileData = [NSData dataWithContentsOfURL:attachmentURL options:0 error:&error];
if (fileData == nil) {
// 'error' should now contain a non-nil value.
// Use this information to handle the error somehow
}

Capturing Signature to Core Data

I have an app that creates a field for the user to sign their name. Upon clicking the save signature I want to create the image, save it as a png, and save it to core data.
"Pilot Signature" is it's own entity, with the property image.
- (IBAction)saveSignature:(id)sender) {
NSData *imageData = UIImagePNGRepresentation(mySignatureImage.image);
// Create an image object for the new image.
NSManagedObject *image =
[NSEntityDescription insertNewObjectForEntityForName:#"Image"
inManagedObjectContext:self.managedObjectContext];
self.mySignatureImage = imageData;
// Set the image for the image managed object.
[image setValue:image forKey:#"PilotSignatureImage"];
}
I get one error and one warning when I invoke saveSignature
expected methody body
And on self.MySignature.image line I get
incompatible types assigning to 'UIImageView" from "NSManagedObject"
I've looked similar posts on here about how to save image to core data, and I'm not having any luck figuring out what I did differently.
Any help would be appreciated
This code has serious problems. First, this line is not valid Objective-C:
- (IBAction)saveSignature:(id)sender) {
That last ) should not be there. This would probably explain an "expected method body" error, because you're confusing the compiler.
There's no self.MySignature.image line. I'm guessing that you mean the line that assigns a value to self.mySignatureImage.
self.mySignatureImage = imageData;
What that error is telling you is that self.mySignatureImage is a UIImageView but that imageData is an NSManagedObject. You can't assign one of those to the other, because they're completely unrelated things. Maybe you meant to type self.mySignature.image here instead, since you mentioned that in your question?
Finally this line doesn't make any sense:
[image setValue:image forKey:#"PilotSignatureImage"];
You're assigning image as an attribute of itself. That's got to be wrong. Maybe you want to be assigning imageData here?
I'm guessing that the last couple of lines should look like this, but it's impossible to be certain from the question:
self.mySignature.image = imageData;
[image setValue:imageData forKey:#"PilotSignatureImage"];
From this question and other related questions that you've asked, I think you would do well to review some of the basics of Objective-C. You seem to be having basic problems that aren't directly related to Core Data or image handling.

How do I have Core Data managedObjects created from JSON file and have them persist between app launches? [duplicate]

This question already has an answer here:
Checking for duplicates when importing to CoreData
(1 answer)
Closed 8 years ago.
I have a bunch of NSManagedObjects that are created from a JSON file online. Currently, I am creating them all each time the app launches (not ideal).
What is the best way to check to see if the objects are already there before I try to create them?
if I do [self saveContext] it seems to work, but as I don't know how to check if they are already loaded, it ends up duplicating everything.
Obviously, I am relatively new to Core Data and seem to be missing a key concept.
[EDIT] After reading more and more about where and when to load this many objects into Core Data, it looks like pre-loading the data is the best option for me (the data is static and will likely only be update a few times per year).
I chose not to use the "find or create pattern" as I assumed it would be more expensive given the number of objects that need to be checked/created and would like to save learning about background queues for next time ;)
I was then having trouble getting the sqlite file to work, and solved it by saving the context after each object was created, rather than once after all the objects were loaded.
The way this is handled usually in my experience is via one of the two options:
You first check if the item exists, and if it does, then you update it, else insert it. Here's a sample of what I have used in the past for a vouchers model:
Voucher *newObject = nil;
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"Voucher"];
request.predicate = [NSPredicate predicateWithFormat:#"voucher_id = %#",[dictionary objectForKey:#"voucher_id"]];
NSError *error = nil;
NSArray *matches = [context executeFetchRequest:request error:&error];
if ([matches count] == 0 ){
newObject = [NSEntityDescription insertNewObjectForEntityForName:#"Voucher" inManagedObjectContext:context];
newObject.number = [json_dictionary objectForKey:#"number"];
newObject.valid_from = [json_dictionary objectForKey:#"valid_from"];
newObject.valid_to = [json_dictionary objectForKey:#"valid_to"];
}
else {
newObject = [matches lastObject];
newObject.number = [json_dictionary objectForKey:#"number"];
newObject.valid_from = [json_dictionary objectForKey:#"valid_from"];
newObject.valid_to = [json_dictionary objectForKey:#"valid_to"];
newObject.voucher_id = [json_dictionary objectForKey:#"voucher_id"];
}
return newObject;
The other way is to select all, put into an NSOrderedSet, and then run a comparison, and only insert if not in the set.
If you look at "Core Data Performance Optimization and Debugging" on this page https://developer.apple.com/wwdc/videos/ , it's got a great explanation of this
If you haven't worked on it before, the learning curve might be a bit steep. But one good way is to use RestKit.
https://github.com/RestKit/RestKit/wiki/Object-mapping#core-data
Ray Wenderlich has a detailed tutorial on Core Data that show you how to do it step by step: (make sure to turn on Google Translate)
In response to your question under comments, here it is:
create a new file and choose to create datamodel (under Core Data)
add your entities - entities are what you declared as class data models. Note that I have Location, Marker, and Village because I have created those as classes (Location.m/.h, etc)]
Add attributes (properties) associated with those entities.
http://i.stack.imgur.com/wOUvF.png
http://i.stack.imgur.com/5AJGZ.png

Progressbar on file-upload to Amazon S3 for iOS?

I was using the services from Parse a while back, and they had implemented an amazing feature for uploading data, with a method something like this:
PFFile *objectToSave...; //An image or whatever, wrapped in a Parse-file
[objectToSave saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
//Do stuff after upload is complete
} progressBlock:^(int percentDone) {
[someLabel setText:[NSString stringWithFormat:#"%i%#", percentDone, #"%"]];
}];
Which let me keep track of the file-upload. Since Parse only let me upload max 10mb files, I chose to move to the cloud-area to explore a bit. I've been testing with Amazon's S3-service now, but the only way I can find how to upload data is by calling [s3 putObject:request];. This will occupy the main thread until it's done, unless I run it on another thread. Either way, I have no idea of letting my users know how far the upload has come. Is there seriously no way of doing this? I read that some browser-API-version of S3's service had to use Flash, or set all uploads to go through another server, and keep track on that server, but I won't do either of those. Anyone? Thanks.
My users are supposed to be uploading video with sizes up to 15mb, do I have to let them stare at a spinning wheel for an unknown amount of time? With a bad connection, they might have to wait for 15 minutes, but they would stare at the screen in hope the entire time.
Seems like I didn't quite do my homework before posting this question in the first place. I found this great tutorial doing exactly what I was asking for. I would delete my question, but I'll let it stay just in case it might help other helpless people like myself.
Basically, it had a delegate-method for this. Do something like this:
S3PutObjectRequest *por = /* your request/file */;
S3TransferManager *tm = /* your transfer manager */;
por.delegate = self;
tm.delegate = self;
[tm upload: por];
Then use this appropriately named delegate-method:
-(void)request:(AmazonServiceRequest *)request
didSendData:(long long)bytesWritten
totalBytesWritten:(long long)totalBytesWritten
totalBytesExpectedToWrite:(long long)totalBytesExpectedToWrite
{
CGFloat progress = ((CGFloat)totalBytesWritten/(CGFloat)totalBytesExpectedToWrite);
}
It will be called for every packet it uploads or something. Just be sure to set the delegates.
(Not sure if you need both delegates to be set though)

hide registration code from user on iOS

Only a short question here, I would like to know the best place to put my registration code for the user that I get back from the server. I am encrypting it as seen here.
//encrypting
NSString* strToEncrypt =NewPINField.text
NSString* theKey = #\"KeyKeyKeyKey\";
NSData* dataToEncrypt = [strToEncrypt dataUsingEncoding: NSUTF8StringEncoding];
NSData *encryptedData = [dataToEncrypt EncryptWithKey: theKey];
NSLog(#\"Encrypted data: %#\", encryptedData);
//decrypting
NSData* encryptedData = (NSData*)[profileData objectForKey:#\"PIN\"];
NSString* theKey = #\"KeyKeyKeyKey\"; //notice this is the same as above. It MUST be
NSData *decData = [encryptedData DecryptWithKey: theKey ];
currentPIN = [NSString stringWithUTF8String:[decData bytes]];
NSLog(#\"Decrypted pin: %#\", currentPIN);
The only other specification is to hide it / put it somewhere no know would think to look.
I need to save state so it needs to be some sort of plist, I was just wondering if there is a way to hide it a little better than just adding it straight to my plist file.
what would you do?
Any help would be greatly appreciated.
If you need to securely store data, I would highly recommend using the keychain. There is a tutorial on creating a basic keychain app here: http://www.raywenderlich.com/6475/basic-security-in-ios-5-tutorial-part-1
You can safely store data in the keychain without worrying about encrypting it first, since that is handled by the OS. But you can if you want to.
When implementing security, never try to hide things where someone won't look: http://en.wikipedia.org/wiki/Security_through_obscurity

Resources