0

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

enter image description here

Chris Geirman
  • 9,474
  • 5
  • 37
  • 70
  • Are you compiling with optimizations enabled? And if you ignore what the sidebar shows and in the debugger run `po fileData`, what do you get? – Itai Ferber Nov 08 '17 at 02:48
  • I'm not even sure how to know how I'm compiling. How would I tell? Also, where do I run the `po fileData` command? I see a filter box, but that's not it – Chris Geirman Nov 08 '17 at 02:52
  • Please do not post a link to your code, copy and paste the actual (relevant) code into your question, as text. – rmaddy Nov 08 '17 at 02:53
  • @maddy, I understand what you mean but in this case the link to the code was extra and would have just cluttered the question. I added it just in case someone wanted more context. – Chris Geirman Nov 08 '17 at 03:01

1 Answers1

0

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
}
Charles Srstka
  • 16,665
  • 3
  • 34
  • 60
  • Thanks Charles! [Here's a link to the code](https://github.com/chirag04/react-native-mail/blob/master/RNMail/RNMail.m) would you mind including the modifications in your answer? As I said, I'm not very proficient with objective c – Chris Geirman Nov 08 '17 at 02:59
  • I'm not going to rewrite your code for you, if that's what you're asking. That's your job. But it's simple enough; just change the call to use the one that returns an error, and then check what that error is. – Charles Srstka Nov 08 '17 at 03:00
  • No, not asking you to rewrite the code (which isn't my code to begin with). I'm just not sure how to do this bit... 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 – Chris Geirman Nov 08 '17 at 03:04
  • There ya go. Enjoy – Charles Srstka Nov 08 '17 at 03:09
  • In Objective-C, when you have methods that take multiple parameters, you put one of the parameters after each of the colons (`:`). Also you need a `&` before the error in order to pass a pointer. See my edit. – Charles Srstka Nov 08 '17 at 03:12
  • I would also consider getting a book on Objective-C and reading it before working with any more Objective-C code directly. The C family of languages make it very easy to shoot yourself in the foot if you don't know what you're doing. – Charles Srstka Nov 08 '17 at 03:17
  • Ha, for sure. I wasn't actually planning on having to dig in this deep, but you know... problems must be solved. I do understand the basics, but just the very basics and have little practical experience. I guess I know just enough to shoot myself in the foot, haha. Thanks for your help. I'm working through your advice now. – Chris Geirman Nov 08 '17 at 03:19
  • on the NSURL line, Xcode now complains that `No visible @interface for 'NSURLComponents' declares the selector 'url'` – Chris Geirman Nov 08 '17 at 03:27
  • Oh whoops, I've been doing too much Swift lately. In Objective-C it's spelled with upper-case letters. I'll edit the answer. – Charles Srstka Nov 08 '17 at 03:59
  • Brilliant! Thanks so much for your help! It worked great. – Chris Geirman Nov 08 '17 at 04:28