Never getting uploading data progress in google API for ios - iphone

I am using GoogleDrive API in my application to upload files from my application. So far I succeeded and finding good results for uploading all types of files.
I followed Google example to upload files.
I am trying to show the progress, dependent on file size, while uploading. I have gone through many classes in the google given example code but there isn't much result.
Steps followed to get the file uploading progress :
I have found below method In GTLServices.m
- (void)setUploadProgressBlock:(GTLServiceUploadProgressBlock)block {
[uploadProgressBlock_ autorelease];
uploadProgressBlock_ = [block copy];
if (uploadProgressBlock_) {
// As above, we need the fetcher to call us back when bytes are sent.
SEL sentDataSel = #selector(objectFetcher:didSendBytes:totalBytesSent:totalBytesExpectedToSend:);
[[self objectFetcher] setSentDataSelector:sentDataSel];
}
}
After that in MyViewController.m written like this
[self.driveService setUploadProgressBlock:^(GTLServiceTicket *ticket, unsigned long long numberOfBytesRead, unsigned long long dataLength) {
NSLog(#"uploading");
}];
Above NSLog never getting excused because of this I am unable to get uploaded data bytes. By debugging I come across as uploadProgressBlock_ always showing nil. may be this resone my block handler not getting executed.
Please suggest me if I did any mistake to work it out.
If any one have idea to get the bytes of data uploaded to google drive for a file please suggest me. Your suggestions are more useful to my work.
Thanks in advance.
Consolidated Answer by taking our folks suggestions:
Here is the code to get upload progress information
GTLServiceTicket *uploadTicket= [self.driveService executeQuery:query completionHandler:^(GTLServiceTicket *ticket,GTLDriveFile *updatedFile,NSError *error)
{
if (error == nil)
{
[self.delegate completedFileUploadingToGoogleDrive];
NSError *fileDeletionError=nil;
[[NSFileManager defaultManager] removeItemAtPath:absalutePath error:&fileDeletionError];
} else
{
[self.delegate errorOccoredWhileUploadingToGoogleDrive:error];
}
}];
[uploadTicket setUploadProgressBlock:^(GTLServiceTicket *ticket, unsigned long long totalBytesWritten, unsigned long long totalBytesExpectedToWrite) {
[self.delegate uploadedFileInfoInKB:(float)totalBytesExpectedToWrite/1024 and:(float)totalBytesWritten/1024];
}];
Happy Coding!!

I have succeeded in using the upload block callback... assign it to the GTLServiceTicket object you obtain from the executeQuery method.
Sample:
GTLServiceTicket *uploadTicket = [self.driveService executeQuery:query completionHandler:^(GTLServiceTicket *ticket, GTLDriveFile *insertedFile, NSError *error)
{ // completion
}];
[uploadTicket setUploadProgressBlock:^(GTLServiceTicket *ticket, unsigned long long totalBytesWritten, unsigned long long totalBytesExpectedToWrite)
{
// progress
}

I recently used FabioL's answer but in Swift 2.3, it looks like this
let serviceTicket = service.executeQuery(query, completionHandler: { (ticket, insertedFile , error) -> Void in
let myFile = insertedFile as? GTLDriveFile
if error == nil {
alert.title = "Image Uploaded"
alert.message = "100%"
if progressView != nil {
progressView!.progress = 1
}
} else {
print("An Error Occurred! \(error)")
alert.title = "There was an error uploading"
}
})
//update UI on progress
serviceTicket.uploadProgressBlock = {(ticket, written, total) in
if progressView != nil {
let progressCalc: Float = (Float(written)/Float(total))
alert.message = "\(progressCalc*100)%"
progressView!.progress = progressCalc
}
}
As the upload happens it updates a ProgressView and on completion it changes the title and message of an UIAlertViewController

I suspect it may have to do with the lack of the NS_BLOCKS_AVAILABLE #define having been set in your project. If so, then instead of using -setUploadProgressBlock:, I think you need to define a method like:
- (void)ticket:(GTLServiceTicket *)ticket
hasDeliveredByteCount:(unsigned long long)numberOfBytesRead
ofTotalByteCount:(unsigned long long)dataLength;
And then specify it as the callback to use in your code, like:
[self.driveService setUploadProgressSelector:#selector(ticket:hasDeliveredByteCount:ofTotalByteCount:)];
(Search for uploadProgressSelector in GTLService.h; there's a comment there that may be helpful.)

Related

How to get local player score from Game Center

How to get score of local player from Leaderboard Game Center? I tried this code, but it returns nothing. Anybody know how to solve it, or is there better way how to get score?
- (NSString*) getScore: (NSString*) leaderboardID
{
__block NSString *score;
GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];
if (leaderboardRequest != nil)
{
leaderboardRequest.identifier = leaderboardID;
[leaderboardRequest loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
if (error != nil)
{
NSLog(#"%#", [error localizedDescription]);
}
if (scores != nil)
{
int64_t scoreInt = leaderboardRequest.localPlayerScore.value;
score = [NSString stringWithFormat:#"%lld", scoreInt];
}
}];
}
return score;
}
I think, that method have to wait for completion of [leaderboardRequest loadScoresWithCompletionHandler: ...
Is it possible?
Your code appears to not have any bugs that I can see. I would recommend displaying the standard leaderboard interface to see if your code that reports the scores is actually working correctly. If so, you should see the scores in the leaderboard. The code below works in my game, and I know the score reporting is working properly because it shows in the default game center UI.
GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];
leaderboardRequest.identifier = kLeaderboardCoinsEarnedID;
[leaderboardRequest loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error) {
if (error) {
NSLog(#"%#", error);
} else if (scores) {
GKScore *localPlayerScore = leaderboardRequest.localPlayerScore;
CCLOG(#"Local player's score: %lld", localPlayerScore.value);
}
}];
If you aren't sure how, the code below should work to show the default leaderboard (iOS7):
GKGameCenterViewController *gameCenterVC = [[GKGameCenterViewController alloc] init];
gameCenterVC.viewState = GKGameCenterViewControllerStateLeaderboards;
gameCenterVC.gameCenterDelegate = self;
[self presentViewController:gameCenterVC animated:YES completion:^{
// Code
}];
You cannot return score outside the block. In this code first "return score" will be executed before the method "loadScoresWithCompletionHandler". Additionally you haven't set initial value for "score", this method will return completely random value.
I suggest you to put your appropriate code inside the block, instead of:
int64_t scoreInt = leaderboardRequest.localPlayerScore.value;
score = [NSString stringWithFormat:#"%lld", scoreInt];
The leaderboard request completes after the return of your method. This means that you are returning a null string.
The method you put the leaderboard request in should be purely for sending the request. The method will be finished executing before the leaderboard request is complete thus your "score = [NSString stringWithFormat:#"%lld", scoreInt];" line is being executed AFTER the return of the "score" which is null until that line is executed.
The solution is to not return the outcome of the completion handler using the method that sends the request. The score is definitely being retrieved correctly, so just do whatever you need to with the score inside of the completion handler. You have no way to know when the completion handler is going to be executed. This, in fact, is the reason why Apple allows you to store the code to be executed in a block! Although, it can be confusing to understand how to work with blocks that will definitely be executed later, or in your situation, sometime after the method is returning.
The best way to handle your situation is to not return anything in this method and just use the "score" variable as you intend to after the block has set score to a non-null value!

Structuring async networking code in controllers

I've just recently switched from ASIHttpRequest library to AFNetworking. I really like the simplicity, but I am still struggling to understand how to structure my async code.
Please consider this sign up scenario.
First I want to check if the entered email adresse is available.
Next I want to check if the entered username is available.
If both the above is valid and available I want to submit my real signup request.
My code would be looking something like.
- (void)signUp{
BOOL hasValidEmail = [self validateEmail:email];
BOOL hasValidUsername = [self validateUsername:username];
if(!hasValidEmail){
NSLog(#"Invalid email");
return;
}
if(!hasValidUsername){
NSLog(#"Invalid username");
return;
}
if (hasValidEmail && hasValidUsername) {
NSLog(#"Go ahead and create account");
}
}
I'm not quite sure how to structure this considering the async nature of my networking methods. Often last condition will be reached before the two previous availability checks have received their response.
The availability checking methods would look something like:
- (BOOL)validateEmail:(NSString*)email{
__block NSString* emailAlreadyExists = #"";
NSString* url = [NSString stringWithFormat:#"user/emailexists/%#", email];
[[APIClient sharedClient] getPath:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
emailAlreadyExists = [responseObject valueForKey:#"exists"];
} failure:^(AFHTTPRequestOperation *operation, NSError* error) {
NSLog(#"Email availability check failed: %#", error.localizedDescription);
}];
if([emailAlreadyExists isEqualToString:#"true"]){
return NO;
}
return YES;
}
Maybe it's just my blocks skills that needs improving, but I'd really like to hear how you would you structure a scenario like this?
Though code samples would be "nice", I'm really looking for patterns or good techniques you know of.
Thanks.
I usually break these things into steps and start the next step when the previous one succeeds. Blocks are great to pass along for this purpose.
This obviously wont compile, but hopefully it can give you some idea of how to do this:
typedef enum
{
SignupErrorNetworkError,
SignupErrorEmailAlreadyTaken,
SignupErrorUsernameAlreadyTaken,
} SignupError;
typedef enum
{
// These steps must be performed in this order.
SignupStepValidateEmail,
SignupStepValidateUsername,
SignupStepCreateAccount,
} SignupStep;
typedef void (^SignupSuccessBlock)();
typedef void (^SignupFailureBlock)(SignupError reason);
// Call this to sign up.
- (void)signupWithSuccess:(SignupSuccessBlock)success failure:(SignupFailureBlock)failure
{
// Start the first step of the process.
[self performSignupStep:SignupStepValidateEmail success:success failure:failure];
}
// Internal method. Don't call this from outside.
- (void)performSignupStep:(SignupStep)step success:(SignupSuccessBlock)success failure:(SignupFailureBlock)failure
{
switch (step)
{
case SignupStepValidateEmail:
[[APIClient sharedClient] getPath:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
if ([responseObject valueForKey:#"exists"])
{
if (failure) failure(SignupErrorEmailAlreadyTaken);
return; }
}
// Start next async step in signup process.
[self performSignupStep:SignupStepValidateUsername success:success failure:failure];
} failure:^(AFHTTPRequestOperation *operation, NSError* error) {
if (failure) failure(SignupErrorNetworkError);
}];
break;
case SignupStepValidateUsername:
// Similar to the step above. Starts the create account step on success.
break;
case SignupStepCreateAccount:
// Similar to the step above. Call the success block when done.
break;
}
}
If the switch is getting too long and ugly you could also make the steps into separate methods and delete the step-enum: validateEmailWithSuccess:failure which continues by calling validateUsernameWithSuccess:failure etc.
I just wanted to emphasize the state machine nature of the process in the example above.

UIManagedDocument - Validating Core Data Entity

I have an app that uses Core Data and it gets its ManagedObjectContext by using UIManagedObject. From reading, I see that I am not suppose to save the context directly - rather I should depend on autosaving of UIManagedObject or use saveToURL:... My issue is that I want to validate the data being stored in my entity. I have constraints on the entity that specify that the min length for the string properties is 1. However, I can create a new object, assign its properties empty strings, and save the file. In the completion handler of saveToURL:... it always has a true success value. I then created my own validator for the name property of my entity. I used sample code from the Core Data Programming Guide -
-(BOOL)validateName:(id *)ioValue error:(__autoreleasing NSError **)outError
{
if (*ioValue == nil)
{
if (outError != NULL)
{
NSString *errorStr = #"nil error";
NSDictionary *userInfoDict = [NSDictionary dictionaryWithObject:errorStr
forKey:NSLocalizedDescriptionKey];
NSError __autoreleasing *error = [[NSError alloc] initWithDomain:#"domain"
code:1
userInfo:userInfoDict];
*outError = error;
}
return NO;
}
else if( [*ioValue length] == 0 )
{
if (outError != NULL) {
NSString *errorStr = #"length error";
NSDictionary *userInfoDict = [NSDictionary dictionaryWithObject:errorStr
forKey:NSLocalizedDescriptionKey];
NSError __autoreleasing *error = [[NSError alloc] initWithDomain:#"domain"
code:1
userInfo:userInfoDict];
*outError = error;
}
return NO;
}
else
{
return YES;
}
}
When this runs, I see that the ioValue has 0 length and that it returns NO, but then my completion handler is never called. Any help would be great.
Is there something I am missing for how to handle saving errors with UIManagedDocument - particularly how to notify the calling code that an error happened while saving its information.
As a rule, you should only call saveToURL to create a brand new file. Let auto-save do the rest.
Also, I'm not sure I follow your question. If you are asking how to know about save failures, the best you can do is register for notifications (since all saves happen on a background thread).
Directly from the documentation:
A UIDocument object has a specific state at any moment in its life cycle. You can check the current state by querying the documentState property. And you can be notified of changes in the state of a document by observing the UIDocumentStateChangedNotification notification.
I guess I need to implement handleError:(NSError *)error userInteractionPermitted:(BOOL)userInteractionPermitted in a subclass of the UIManagedDocument. I found that via this article - http://blog.stevex.net/2011/12/uimanageddocument-autosave-troubleshooting/

Custom content printing in iphone?

I am a new bee to iphone programming and I need some help with printing.
I have a view with UIScrollView,UITextView and UIImage as its subviews. I would like to print this view such that the complete content of the scroll view and text view will available be available on the printed page. I went through the UIPrintFormatter but I am not sure of how to use it for my requirement. It would be really great if someone could give me a good answer(example\sample code) for my problem.
Thanks a lot in advance!
Came randomly to this question. No answer yet! Little help from code,
- (void) didPressPrintExpenseButton {
void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) =
^(UIPrintInteractionController *pic, BOOL completed, NSError *error) {
if (!completed && error) NSLog(#"Print error: %#", error);
};
NSData *pdfData = [self generatePDFDataForPrinting];
printController.printingItem = pdfData;
[printController presentAnimated:YES completionHandler:completionHandler];
}

How can I use NSError in my iPhone App?

I am working on catching errors in my app, and I am looking into using NSError. I am slightly confused about how to use it, and how to populate it.
Could someone provide an example on how I populate then use NSError?
Well, what I usually do is have my methods that could error-out at runtime take a reference to a NSError pointer. If something does indeed go wrong in that method, I can populate the NSError reference with error data and return nil from the method.
Example:
- (id) endWorldHunger:(id)largeAmountsOfMonies error:(NSError**)error {
// begin feeding the world's children...
// it's all going well until....
if (ohNoImOutOfMonies) {
// sad, we can't solve world hunger, but we can let people know what went wrong!
// init dictionary to be used to populate error object
NSMutableDictionary* details = [NSMutableDictionary dictionary];
[details setValue:#"ran out of money" forKey:NSLocalizedDescriptionKey];
// populate the error object with the details
*error = [NSError errorWithDomain:#"world" code:200 userInfo:details];
// we couldn't feed the world's children...return nil..sniffle...sniffle
return nil;
}
// wohoo! We fed the world's children. The world is now in lots of debt. But who cares?
return YES;
}
We can then use the method like this. Don't even bother to inspect the error object unless the method returns nil:
// initialize NSError object
NSError* error = nil;
// try to feed the world
id yayOrNay = [self endWorldHunger:smallAmountsOfMonies error:&error];
if (!yayOrNay) {
// inspect error
NSLog(#"%#", [error localizedDescription]);
}
// otherwise the world has been fed. Wow, your code must rock.
We were able to access the error's localizedDescription because we set a value for NSLocalizedDescriptionKey.
The best place for more information is Apple's documentation. It really is good.
There is also a nice, simple tutorial on Cocoa Is My Girlfriend.
I would like to add some more suggestions based on my most recent implementation. I've looked at some code from Apple and I think my code behaves in much the same way.
The posts above already explain how to create NSError objects and return them, so I won't bother with that part. I'll just try to suggest a good way to integrate errors (codes, messages) in your own app.
I recommend creating 1 header that will be an overview of all the errors of your domain (i.e. app, library, etc..). My current header looks like this:
FSError.h
FOUNDATION_EXPORT NSString *const FSMyAppErrorDomain;
enum {
FSUserNotLoggedInError = 1000,
FSUserLogoutFailedError,
FSProfileParsingFailedError,
FSProfileBadLoginError,
FSFNIDParsingFailedError,
};
FSError.m
#import "FSError.h"
NSString *const FSMyAppErrorDomain = #"com.felis.myapp";
Now when using the above values for errors, Apple will create some basic standard error message for your app. An error could be created like the following:
+ (FSProfileInfo *)profileInfoWithData:(NSData *)data error:(NSError **)error
{
FSProfileInfo *profileInfo = [[FSProfileInfo alloc] init];
if (profileInfo)
{
/* ... lots of parsing code here ... */
if (profileInfo.username == nil)
{
*error = [NSError errorWithDomain:FSMyAppErrorDomain code:FSProfileParsingFailedError userInfo:nil];
return nil;
}
}
return profileInfo;
}
The standard Apple-generated error message (error.localizedDescription) for the above code will look like the following:
Error Domain=com.felis.myapp Code=1002 "The operation couldn’t be completed. (com.felis.myapp error 1002.)"
The above is already quite helpful for a developer, since the message displays the domain where the error occured and the corresponding error code. End users will have no clue what error code 1002 means though, so now we need to implement some nice messages for each code.
For the error messages we have to keep localisation in mind (even if we don't implement localized messages right away). I've used the following approach in my current project:
1) create a strings file that will contain the errors. Strings files are easily localizable. The file could look like the following:
FSError.strings
"1000" = "User not logged in.";
"1001" = "Logout failed.";
"1002" = "Parser failed.";
"1003" = "Incorrect username or password.";
"1004" = "Failed to parse FNID."
2) Add macros to convert integer codes to localized error messages. I've used 2 macros in my Constants+Macros.h file. I always include this file in the prefix header (MyApp-Prefix.pch) for convenience.
Constants+Macros.h
// error handling ...
#define FS_ERROR_KEY(code) [NSString stringWithFormat:#"%d", code]
#define FS_ERROR_LOCALIZED_DESCRIPTION(code) NSLocalizedStringFromTable(FS_ERROR_KEY(code), #"FSError", nil)
3) Now it's easy to show a user friendly error message based on an error code. An example:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:FS_ERROR_LOCALIZED_DESCRIPTION(error.code)
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
Great answer Alex. One potential issue is the NULL dereference. Apple's reference on Creating and Returning NSError objects
...
[details setValue:#"ran out of money" forKey:NSLocalizedDescriptionKey];
if (error != NULL) {
// populate the error object with the details
*error = [NSError errorWithDomain:#"world" code:200 userInfo:details];
}
// we couldn't feed the world's children...return nil..sniffle...sniffle
return nil;
...
Objective-C
NSError *err = [NSError errorWithDomain:#"some_domain"
code:100
userInfo:#{
NSLocalizedDescriptionKey:#"Something went wrong"
}];
Swift 3
let error = NSError(domain: "some_domain",
code: 100,
userInfo: [NSLocalizedDescriptionKey: "Something went wrong"])
Please refer following tutorial
i hope it will helpful for you but prior you have to read documentation of NSError
This is very interesting link i found recently ErrorHandling
I'll try summarize the great answer by Alex and the jlmendezbonini's point, adding a modification that will make everything ARC compatible (so far it's not since ARC will complain since you should return id, which means "any object", but BOOL is not an object type).
- (BOOL) endWorldHunger:(id)largeAmountsOfMonies error:(NSError**)error {
// begin feeding the world's children...
// it's all going well until....
if (ohNoImOutOfMonies) {
// sad, we can't solve world hunger, but we can let people know what went wrong!
// init dictionary to be used to populate error object
NSMutableDictionary* details = [NSMutableDictionary dictionary];
[details setValue:#"ran out of money" forKey:NSLocalizedDescriptionKey];
// populate the error object with the details
if (error != NULL) {
// populate the error object with the details
*error = [NSError errorWithDomain:#"world" code:200 userInfo:details];
}
// we couldn't feed the world's children...return nil..sniffle...sniffle
return NO;
}
// wohoo! We fed the world's children. The world is now in lots of debt. But who cares?
return YES;
}
Now instead of checking for the return value of our method call, we check whether error is still nil. If it's not we have a problem.
// initialize NSError object
NSError* error = nil;
// try to feed the world
BOOL success = [self endWorldHunger:smallAmountsOfMonies error:&error];
if (!success) {
// inspect error
NSLog(#"%#", [error localizedDescription]);
}
// otherwise the world has been fed. Wow, your code must rock.
Another design pattern that I have seen involves using blocks, which is especially useful when a method is being run asynchronously.
Say we have the following error codes defined:
typedef NS_ENUM(NSInteger, MyErrorCodes) {
MyErrorCodesEmptyString = 500,
MyErrorCodesInvalidURL,
MyErrorCodesUnableToReachHost,
};
You would define your method that can raise an error like so:
- (void)getContentsOfURL:(NSString *)path success:(void(^)(NSString *html))success failure:(void(^)(NSError *error))failure {
if (path.length == 0) {
if (failure) {
failure([NSError errorWithDomain:#"com.example" code:MyErrorCodesEmptyString userInfo:nil]);
}
return;
}
NSString *htmlContents = #"";
// Exercise for the reader: get the contents at that URL or raise another error.
if (success) {
success(htmlContents);
}
}
And then when you call it, you don't need to worry about declaring the NSError object (code completion will do it for you), or checking the returning value. You can just supply two blocks: one that will get called when there is an exception, and one that gets called when it succeeds:
[self getContentsOfURL:#"http://google.com" success:^(NSString *html) {
NSLog(#"Contents: %#", html);
} failure:^(NSError *error) {
NSLog(#"Failed to get contents: %#", error);
if (error.code == MyErrorCodesEmptyString) { // make sure to check the domain too
NSLog(#"You must provide a non-empty string");
}
}];
extension NSError {
static func defaultError() -> NSError {
return NSError(domain: "com.app.error.domain", code: 0, userInfo: [NSLocalizedDescriptionKey: "Something went wrong."])
}
}
which I can use NSError.defaultError() whenever I don't have valid error object.
let error = NSError.defaultError()
print(error.localizedDescription) //Something went wrong.
Well it's a little bit out of question scope but in case you don't have an option for NSError you can always display the Low level error:
NSLog(#"Error = %# ",[NSString stringWithUTF8String:strerror(errno)]);