Get NSString out of ENNoteContent with Evernote Cloud SDK 2.0 - ios

I am new to Evernote SDK development and am using the evernote cloud SDK 2.0 as recommended by Evernote.
However, I am having trouble to get the NSString content out of the ENNoteContent object. I have tried the followings from searching online but none seems to work with the cloud sdk as I guess they are all for the old version of Evernote SDK...
1 Using "convertENMLToHTML" method.
According to this and this, I could call convertENMLToHTML directly on an ENNoteContent object much like this convertENMLToHTML:note.content. However, in the cloud SDK, this resulted in an exception inside ENMLUtility that terminates the app because convertENMLToHTML is expecting an NSString as opposed to ENNoteContent and the first thing this function does is trying to call [enmlContent dataUsingEncoding:NSUTF8StringEncoding]] which caused the exception if enmlContent is a pointer to ENNoteContent but not a pointer to NSString.
2 Attempting to get _emml object out of the ENNoteContent object
This post has a quote of calling [note.content enml] but this again doesn't work with cloud sdk as object enml isn't defined in the interface.
Does anyone know how one can get an NSString out of ENNoteContent? I would expect this to be a very straightforward process but am surprised that I wasn't able to find anything that works for the Cloud SDK.
3 Using generateWebArchiveData method
Per Sash's answer below, I have also attempted to use the generateWebArchiveData method in the example from the cloud sdk. The code I have looks like this:
[[ENSession sharedSession] downloadNote:result.noteRef progress:^(CGFloat progress) {
} completion:^(ENNote *note, NSError *downloadNoteError) {
if (note) {
NSLog(#"%#", note.title);
[note generateWebArchiveData:^(NSData *data) {
NSString* strContent = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"test content %#", strContent);
}];
} else {
NSLog(#"Error downloading note contents %#", downloadNoteError);
}
}];
However, strContent outputs "null" for a note that I have verified with legitimate content.
As a temporary hack, we added #property (nonatomic, copy) NSString * emml;
in ENNoteContent.h and removed the same line in ENNoteContent.m to get around this for now.

You are close. Technique #1 above is what you want, but as you discovered the enml property is private in the "default" SDK. Import the "advanced" header and you'll have access to note.content.enml. That is a string, and you can send it to convertENMLtoHTML if you prefer an HTML representation.
Do note that there is no "plaintext" string content for an existing note. You'll always see it as markup, and if you want to get rid of the markup, doing so is beyond the scope of the SDK-- how to do that depends very much on what the content you're dealing with looks like.

You should check out their samples included with SDK, seems like
-[ENNote generateWebArchiveData:] will get you HTML NSData in the completion block
https://github.com/evernote/evernote-cloud-sdk-ios/blob/master/Getting_Started.md#downloading-and-displaying-an-existing-note might also help

Related

Saving an iCloud Drive security scoped URL on iOS (UIDocumentPickerViewController)

I'm trying to save the security scoped URL returned from iCloud document picker (UIDocumentPickerViewController)
The documentation states:
If the URL is not a ubiquitous URL, save a bookmark to the file using
the
bookmarkDataWithOptions:includingResourceValuesForKeys:relativeToURL:error:
method and passing in the NSURLBookmarkCreationWithSecurityScope
option. Calling this method creates a bookmark containing a
security-scoped URL that you can use to open the file without further
user intervention.
However, the compiler says that NSURLBookmarkCreationWithSecurityScope is not supported on iOS.
Anyone know what's going on here....?
After further digging, it turns out option NSURLBookmarkCreationWithSecurityScope is NOT needed at all when creating bookmark data in IOS. It's an option for OS X. You can just pass nil for the option field. I think Apple's document is confusing at the best.
However, you do need to call startAccessingSecurityScopedResource before creating the bookmark and make sure the call returns 1 (success) before proceed. Otherwise, bookmark creation will fail. Here is the sample code:
if ([url startAccessingSecurityScopedResource]==1) {
NSError *error;
NSData *bookmark = [url bookmarkDataWithOptions:nil
includingResourceValuesForKeys:nil
relativeToURL:nil
error:&error];
if (error) {
//handle error condition
} else {
// save your bookmark
}
}
[url stopAccessingSecurityScopedResource];
Again Apple's document is confusion at the best! It took me a lot of time to find out this. Hope this helps.
I ran into the same issue today, and indeed the compiler says NSURLBookmarkCreationWithSecurityScope is not available on iOS.
But to my surprise, if I use the raw constant instead (NSURLBookmarkCreationWithSecurityScope maps to ( 1 << 11 ), the method seems to work. It returns a valid bookmark data object, and when I call [[NSURL URLByResolvingBookmarkData:options:relativeToURL:bookmarkDataIsStale:stale], a valid security-scoped NSURL is returned and I can access the files and directories. Also, I tested these with iCloud Drive. And the documentation only says this should work for third-party document providers.
I am not sure how reliable this approach is, because it seems that Apple engineers didn't have time to finish up this feature, so disabled it in the last minute. Or it could be simply a bug in the header file. If anyone finds out more about this, please comment.

AFNetworking 2 AFHTTPRequestOperation failure block stripping keys from error userInfo

I have just updated my app from AFNetworking 1.3.3 to 2.0.1, which required rewriting my network client that used to subclass AFHTTPClient.
I swapped out AFHTTPClient for AFHTTRequestOperationManager (I need to support iOS 6) and everything works fine apart from this:
The server gives me a JSON error string with the details of the error in:
error.userInfo.localizedRecoverySuggestion
However, this key (localizedRecoverySuggestion) is no longer in my NSError object.
Does anybody any idea how I can access it? Or what part of AFNetworking is stripping it out? The server is still sending it, it just doesn't make it as for as the error object in my POST: etc methods.
I've spent some time on this and I'm struggling to find where the issue is.
After a spot of debugging, it looks like the data takes the following path through AFNetworking:
AFURLConnectionManager connection:didReceiveData:
AFURLResponseSerialization validateResponse:data:error:
At which point it is thrown away.
So as a quick fix I just added an extra dictionary entry to that method where userInfo is created as follows:
NSLocalizedRecoverySuggestionErrorKey: [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]
This is obviously a complete hack, but if anyone could give a pointer on how to accomplish this correctly, I'd be very grateful.

When using the Pocket API in an iOS app, is retrieval of articles only handled through JSON?

For those that have integrated Pocket into an app (further than just saving articles, I need to retrieve) when you go to retrieve a list of the users articles, is it only handled through JSON (as discussed here), or can you do it somehow with the Objective-C SDK directly?
If so, would I just be best off using a JSON framework to integrate it into my app?
I only ask because there appears to be a native way to save articles, and I was hoping there was a way to retrieve them as well, but I can't seem to find anything about it listed.
If you check out the source of the SDK on Github, you'll see there is a method to call any API. So it does appear that you can use the SDK to do more than just share.
Edit: You'd probably need to do something like this (untested code)
NSDictionary* argumentDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
#"010101", #"consumer_key",
#"101010", #"access_token",
#"simple", #"detailType", nil]; //etc
[[PocketAPI sharedAPI] callAPIMethod:#"get"
withHTTPMethod:#"POST"
arguments:argumentDictionary
handler:^(PocketAPI *api, NSString *apiMethod, NSDictionary *response, NSError *error){
// handle response here!
}];

Is it possible to use the Google Translate api with iOS?

How do I use the google translate API with iOS 6.0? I have tried googling the documentation and tried to research it, but I can't find anything that is updated since google made the api to be no longer free.
The only thing I have been able to find was this, but it didn't really help much because I need to use the api key that I have, but I have no idea how to.
http://www.raywenderlich.com/1448/how-to-translate-text-with-google-translate-and-json-on-the-iphone
This seems up to date: https://developers.google.com/translate/v2/getting_started
(completely meta: Oops! Your answer couldn't be submitted because:
body must be at least 30 characters; you entered 23)
Yes, it is. Once you get your Google key, just plug it into FGTranslator. Note, generate a "server" key, since the Google Translate API does not currently support iOS keys.
It's just a one-line call to the translate function after that.
FGTranslator *translator = [[FGTranslator alloc] initWithGoogleAPIKey:#"your_google_key"];
[translator translateText:#"Bonjour!"
completion:^(NSError *error, NSString *translated, NSString *sourceLanguage)
{
NSLog(#"translated from %#: %#", sourceLanguage, translated);
}];

Using output parameters with ARC

So I have read this question, which seems to be exactly the kind of problem I am having, but the answer in that post does not solve my problem. I am attempting to write a data serialization subclass of NSMutableData. The problematic function header looks like this:
-(void)readString:(__autoreleasing NSString **)str
I do some data manipulation in the function to get the particular bytes the correspond to the next string in the data stream, and then I call this line:
*str = [[NSString alloc] initWithData:strData encoding:NSUTF8StringEncoding];
No errors in this code. But when I try to call the function like so:
+(id) deserialize:(SerializableData *)data
{
Program *newProgram = [[Program alloc] init];
[data readString:&(newProgram->programName)];
On the line where I actually call the function, I get the following error:
Passing address of non-local object to __autoreleasing parameter for write-back
I have tried placing the __autoreleasing in front of the NSString declaration, in front of the first *, and between the two *'s, but all configurations generate the error.
Did I just miss something when reading the other question, or has something in the ARC compiler changed since the time of that post?
EDIT:
It seems that the problem is coming from the way I am trying to access the string. I can work around it by doing something like this:
NSString* temp;
[data readString&(temp)];
newProgram.programName = temp;
but I would rather have direct access to the ivar
You can't. You might gain insight from LLVM's document Automatic Reference Counting, specifically section 4.3.4. "Passing to an out parameter by writeback". However, there really isn't that much extra detail other than you can't do that (specifically, this isn't listed in the "legal forms"), which you've already figured out. Though maybe you'll find the rationale interesting.

Resources