Posting comment to YouTube with GData ObjC client library fails - objective-c

I'm trying to implement commenting on YouTube videos with the gdata-objectivec-client library, using the code snippet posted in this thread; copy follows:
- (void)addCommentTitle:(NSString *)commentTitle
text:(NSString *)commentContent
toVideo:(GDataEntryYouTubeVideo *)entry {
GDataComment *commentObj = [entry comment];
GDataFeedLink *feedLink = [commentObj feedLink];
NSURL *feedURL = [feedLink URL];
if (feedURL) {
// fetch the comment feed for the video
GDataServiceGoogleYouTube *service = [self youTubeService];
[service fetchFeedWithURL:feedURL
completionHandler:^(GDataServiceTicket *ticket, GDataFeedBase *commentFeed, NSError *error) {
// callback
//
// insert a new comment into the comment feed
if (error == nil) {
GDataEntryYouTubeComment *newCommentEntry = [GDataEntryYouTubeComment commentEntry];
[newCommentEntry setTitleWithString:commentTitle];
[newCommentEntry setContentWithString:commentContent];
NSURL *postURL = [[commentFeed postLink] URL];
[service fetchEntryByInsertingEntry:newCommentEntry
forFeedURL:postURL
completionHandler:^(GDataServiceTicket *ticket, GDataEntryBase *entry, NSError *error) {
// callback
if (error == nil) {
// succeeded
}
}];
}
}];
}
}
but I always get the following exception:
*** Assertion failure in -[GDataObject setContentStringValue:](), XXXXXXXX/GData/BaseClasses/GDataObject.m:2353
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'GDataEntryYouTubeComment setting undeclared content value'
Luckily enough, I managed to make this go away by adding a new call before the comment contents are set:
GDataEntryYouTubeComment* newCommentEntry = [GDataEntryYouTubeComment commentEntry];
[newCommentEntry addContentValueDeclaration]; // <--- this method does the trick
[newCommentEntry setTitleWithString:commentTitle];
[newCommentEntry setContentStringValue:commentContent];
but it's still not OK as the request now bounces back from the server with this error:
serviceBase:<GDataServiceGoogleYouTube: 0x7a73eb0>
objectFetcher:GTMHTTPFetcher 0x7c75b20 (https://gdata.youtube.com/feeds/api/videos/XXXXXXXXXX/comments)
failedWithStatus:400
data:<errors xmlns='http://schemas.google.com/g/2005'><error><domain>GData</domain><code>ParseException</code><internalReason>[Line 2, Column 514, element entry] No converter for type class java.lang.Void</internalReason></error><error><domain>GData</domain><code>missingConverter</code><internalReason>No converter for type class java.lang.Void</internalReason></error></errors>
Has anyone else run into this issue? Is this an error on my side or Google's side?

Turns out the above code is correct, in my code I misspelled
[newCommentEntry setContentWithString:commentContent];
and used
[newCommentEntry setContentStringValue:commentContent];
instead. Now it works fine.

Related

Core data disable journal_mode don't work

I want to disable the journal mode in my core data app.
This is the code:
- (NSPersistentContainer *)persistentContainer {
// The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.
#synchronized (self) {
if (_persistentContainer == nil) {
_persistentContainer = [[NSPersistentContainer alloc] initWithName:#"My_App"];
NSURL *url = [[self applicationFilesDirectory] URLByAppendingPathComponent:#"My_App.sqlite"];
NSPersistentStoreDescription *description=[[NSPersistentStoreDescription alloc]initWithURL:url];
NSMutableDictionary *pragmaOptions=[NSMutableDictionary dictionary];
[pragmaOptions setObject:#"DELETE" forKey:#"journal_mode"];
[description setOption:pragmaOptions forKey:#"NSQlitePragmaOptions"];
_persistentContainer.persistentStoreDescriptions=#[description];
[_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
if (error != nil) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
NSLog(#"Unresolved error %#, %#", error, error.userInfo);
abort();
}
}];
}
}
return _persistentContainer;}
I also verified with this:
NSArray *descriptionArray=[_persistentContainer persistentStoreDescriptions];
NSPersistentStoreDescription * description=[descriptionArray objectAtIndex:0];
NSLog(#"%#",description.options);
and the result of NSLog is:
{
NSInferMappingModelAutomaticallyOption = 1;
NSMigratePersistentStoresAutomaticallyOption = 1;
NSQlitePragmaOptions = {
"journal_mode" = DELETE;
};
but when I restart my app I always find in the application directory all the three file My_App.sqlite, My_App.sqlite-shm and My_App.sqlite-wal.
Why doesn't it work?

Error 3840 with self hosted parse server 2.2.9 and iOS sdk 1.13

In my app delegate, I call
[Parse initializeWithConfiguration:[ParseClientConfiguration configurationWithBlock:^(id<ParseMutableClientConfiguration> configuration) {
configuration.applicationId = #"MYAPPKEY";
configuration.clientKey = #"";
configuration.server = #"DOMAIN/parse";
}]];
// test parse
PFObject *gameScore = [PFObject objectWithClassName:#"TestObject"];
gameScore[#"foo"] = #"bar";
[gameScore saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (succeeded) {
// The object has been saved.
NSLog(#"parse is working");
} else {
// There was a problem, check error.description
NSLog(#"parse is not working: %#",error);
}
}];
and I get the following error:
Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
I get the error from any call to parse.
My server works well with the Android SDK and the JS SDK, but I keep getting this error on iOS. I've added my domain to the App Transport Security Settings.
You can not leave the clientKey empty. The parse server does not use clientKey any more but it still crashes when its null.
configuration.clientKey = #"47b6r78tb3ynf907ynoe";
You should try with adding a / after the
configuration.server = #"DOMAIN/parse";
so it looks like
configuration.server = #"DOMAIN/parse/";

Google Drive API - list specific files in a specific folder using Objective-C

I'm working on a Google Drive integration for iOS and I've hit a snag—I need to check for the existence of a file in a folder, but I keep getting a "500 Internal Error" response no matter how I seem to put together the request. I think this should be legit:
// self.directoryDriveFile.identifier is a valid folder identifier retrieved on previous request
GTLQueryDrive *query = [GTLQueryDrive queryForChildrenListWithFolderId:self.directoryDriveFile.identifier];
// add query to specify the file we're interested in (works in Java version...)
query.q = [NSString stringWithFormat:#"title='%#' and trashed=false",
ZTCloudSyncLockFileName];
// stopping in debugger shows query.q: title='sync.lock' and trashed=false
// fire off request
[self.driveService executeQuery:query
completionHandler:^(GTLServiceTicket *ticket,
GTLDriveFileList *files,
NSError *error) {
if (error == nil) {
if ([files.items count] > 0) {
self.foundLockfile = YES;
} else {
self.foundLockfile = NO;
}
} else {
DLog(#"An error occurred loading lockfile request: %#", error);
[self bailWithError:error performCleanup:NO];
}
}];
When the query is executed, it always ends up in error, with the following unfortunately sparse error information:
Error Domain=com.google.GTLJSONRPC
ErrorDomain Code=500 "The operation couldn’t be completed. (Internal Error)"
UserInfo=0x99c4660 {
error=Internal Error,
GTLStructuredError=GTLErrorObject 0x99c4360: {
message:"Internal Error" code:500 data:[1]},
NSLocalizedFailureReason=(Internal Error)}
I've also tried the following more basic query, specifying a parents clause, but I end up with the same unfortunately spare error object shown above:
GTLQueryDrive *altQuery = [GTLQueryDrive queryForFilesList];
altQuery.q = [NSString stringWithFormat:#"title='%#' and trashed=false and '%#' in parents",
ZTCloudSyncLockFileName,
self.directoryDriveFile.identifier];
That, too, should work, but also produces a 500 error.
Additional information: tested the following while working on this:
Check for folder in directory root—OK
Create folder in directory root—OK
Check for file named sync.lock in directory root—OK
-(void)fetchGoogleDriveFileListWithfolderId:(NSString *)folderId
:(void (^)(NSMutableArray *, NSError*))completionBlock
{
GTLQueryDrive *query = [GTLQueryDrive queryForFilesList];
query.q =[NSString stringWithFormat:#"'%#' in parents and trashed=false", folderId];
GTLServiceTicket *ticketListing = [self.driveService
executeQuery:query completionHandler:^(GTLServiceTicket *ticket,GTLDriveFileList *files, NSError *error)
{
NSMutableArray *mainArray=[[NSMutableArray alloc]init];
if (error == nil)
{
completionBlock(files.items,nill);
}
else
{
NSLog(#"An error occurred: %#", error);
completionBlock(nil,error);
}
}];
}
You can use above method for fetch the folder contents.
Here folderId is
“root” (Main Drive)
“sharedWithMe” for shared folder
GTLDrivefile identifier value

EXC_BAD_ACCESS during NSFileVersion call to removeOtherVersionsOfItemAtURL: inside coordinated write block

I'm using what seems to be a simple invocation of the NSFileVersion class method removeOtherVersionsOfItemAtURL: inside a coordinated writing block for some iCloud conflict resolution.
When my devices go into 'spaz mode', which is a technical term for repeatedly opening and closing the application on a few devices, an EXC_BAD_ACCESS exception is thrown internally. Code snippet:
- (void)compareVersionChanges:(NSFileVersion *)version {
if (![DataLoader iCloudPreferenceEnabled]) {
NSLog(#"Ignoring iCloud changes (version comparison) based on user preference");
return;
}
NSLog(#"compareVersionChanges");
dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(aQueue, ^(void) {
NSError *readError = nil;
NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] initWithFilePresenter:(id)self];
[coordinator coordinateReadingItemAtURL:[version URL] options:0 error:&readError byAccessor:^(NSURL *newURL) {
DataContext *loadedContext = nil;
NSData *data = [NSData dataWithContentsOfURL:newURL];
NSError *e = nil;
loadedContext = [self convertXmlDataToContext:data error:&e];
if (e) {
NSLog(#"Done loading, error: %#", e);
[[DataLoader applicationDelegate] displayError:e];
loadedContext = nil;
}
if (!loadedContext) {
return;
}
id appDelegate = [DataLoader applicationDelegate];
DataContext *inMemoryContext = nil;
if (appDelegate != nil && [appDelegate respondsToSelector:#selector(context)]) {
inMemoryContext = [appDelegate performSelector:#selector(context)];
}
if (inMemoryContext) {
NSLog(#"Performing iCloud context synchronizating...");
DataContextSynchronizer *synchronizer = [[DataContextSynchronizer alloc] init];
ChangeSet *changes = [synchronizer compareLocalContext:inMemoryContext andRemoteContext:loadedContext];
if ([[changes changes] count] > 0) {
[SelectionManager disable];
#synchronized(appDelegate) {
NSLog(#"Applying synchronization changes...");
[synchronizer applyChangeSet:changes toDataContext:inMemoryContext];
NSLog(#"Synchronization changes applied");
}
[SelectionManager enable];
if ([appDelegate respondsToSelector:#selector(setSkipRefreshSave:)]) {
[appDelegate performSelector:#selector(setSkipRefreshSave:) withObject:[NSNumber numberWithBool:YES]];
}
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(mainQueue, ^(void) {
[SelectionManager notifyListeners];
});
if ([appDelegate respondsToSelector:#selector(setSkipRefreshSave:)]) {
[appDelegate performSelector:#selector(setSkipRefreshSave:) withObject:[NSNumber numberWithBool:NO]];
}
[self save:[[DataLoader applicationDelegate] context]];
} else {
NSLog(#"No sync changes applicable.");
}
NSError *coordinateWriteRemoveError = nil;
[coordinator coordinateWritingItemAtURL:newURL options:NSFileCoordinatorWritingForDeleting error:&coordinateWriteRemoveError byAccessor:^(NSURL *theURL) {
theURL = [theURL copy];
NSError *removeOtherVersionsError = nil;
[NSFileVersion removeOtherVersionsOfItemAtURL:theURL error:&removeOtherVersionsError];
if (removeOtherVersionsError) {
NSLog(#"Error removing other versions: %#", removeOtherVersionsError);
}
}];
if (coordinateWriteRemoveError) {
NSLog(#"Error occurred coordinating write for deletion of other file versions: %#", coordinateWriteRemoveError);
}
}
}];
if (readError) {
NSLog(#"Done loading (outside block) error: %#", readError);
}
});
}
I thought a little syntax highlighting might make this easier to examine:
Link to image of code snippet and failure stack in Xcode
The error actually occurs on line 1404, and as you can see from the below screenshot, it's deep in Apple code territory.
Link to image of debugger
Before submitting a radar, I thought I'd check here to see if there's something I'm doing wrong? The extra [... copy] on line 1402 was just a quick check to make sure I'm not losing the reference to the block-provided argument, and will be removed.
Edit: An important note! I'm using ARC.
Edit 2: I've noticed that when calling:
[NSFileVersion otherVersionsOfItemAtURL:theURL]
The return value is nil, which indicates (via the documentation):
...or nil if there is no such file. The array does not contain the version object returned by the currentVersionOfItemAtURL: method.
So by checking the return value of this method before I make the call to removeOtherVersionsOfItemAtURL:, it has alleviated the issue. But I still find it strange that an EXC_BAD_ACCESS is thrown, rather than that method handling it properly.
I've noticed that when calling:
[NSFileVersion otherVersionsOfItemAtURL:theURL]
immediately prior to the call to removeOtherVersionsOfItemAtURL:, the return value is nil, which indicates (via the documentation):
Returns: An array of file version objects or nil if there is no such
file. The array does not contain the version object returned by the
currentVersionOfItemAtURL: method.
So by checking the return value of this method before I make the call to removeOtherVersionsOfItemAtURL:, it has alleviated the issue. But I still find it strange that an EXC_BAD_ACCESS is thrown by removeOtherVersionsOfItemAtURL:, rather than that method simply returning NO, or simply populating the provided NSError object.
I'll be filing a Radar and will update here when I hear back.

EXC_BAD_ACCESS using iCloud on multiple devices

I'm creating an app with iCloud. But I have some problem. It creates directory on iCloud using NSFileWrapper, then it creates NSData (container) file in NSFileWrapper directory. I'm using this code to convert NSFileWrapper to NSMutableArray:
NSFileWrapper *MyWrapper=[[[MyDocument data] fileWrappers] objectForKey:#"myFile.doh"];
    NSData *MyData=[NSData dataWithData:[MyWrapper regularFileContents]];
    NSMutableArray *MyList=[NSPropertyListSerialization propertyListFromData:MyData mutabilityOption:NSPropertyListMutableContainers format:nil errorDescription:nil];
And it works correctly only on the device, which has created this container. On other devices the result of this code is BAD_ACCESS (in the second line of the code, where I start doing something with data). While debugging, function "regularFileContents" returns correct object with correct data size, but when I try to read this data, BAD_ACEESS(code=10) happens.
I'm using ARC, so it's not an error of memory management.
May be the problem is in some project/code sign settings? Any ideas?
Thanks!
I ran into this as well and after much experimentation I've found that even though the outer wrapper has downloaded the inner contents have not actually downloaded yet and that causes the call to regularFileContents to fail.
I've been calling startDownloadingUbiquitousItemAtURL on MyWrapper and once that completes the error is gone. Here's a method that checks the downloaded status of a file (assuming you know the url to your MyWrapper) and starts the download if it isn't downloaded yet.
-(BOOL)downloadFileIfNotAvailable:(NSURL*)fileURL
{
NSNumber *isInCloud = nil;
if ([fileURL getResourceValue:&isInCloud forKey:NSURLIsUbiquitousItemKey error:nil])
{
if ([isInCloud boolValue]) {
NSNumber *isDownloaded = nil;
if ([fileURL getResourceValue:&isDownloaded forKey:NSURLUbiquitousItemIsDownloadedKey error:nil])
{
if ([isDownloaded boolValue])
{
return YES;
}
NSError *error = nil;
[[NSFileManager defaultManager] startDownloadingUbiquitousItemAtURL:fileURL error:&error];
if (error)
{
NSLog(#"Download Failed :: %#", error);
}
return NO;
}
}
}
return YES;
}