How to sucessfully call a BOOL method in an if statement? [duplicate] - ios

This question already has answers here:
Return value for function inside a block
(3 answers)
Closed 8 years ago.
Updated:
I am trying to call a method from a different class and put it in an if statement saying "if the uploadPhoto method is true then display success for testing purposes" here is my updated code:
PhotoScreen *script = [[PhotoScreen alloc] init];
if ([script uploadPhoto])
{
NSLog(#"Sucess!");
}
It isn't giving me the error anymore but when I summit the photo from the uploadPhoto method, it does't log the "Success" And here is my uploadPhoto method:
- (BOOL)uploadPhoto
{
//upload the image and the title to the web service
[[API sharedInstance] commandWithParams:[NSMutableDictionary dictionaryWithObjectsAndKeys:
#"upload",#"command",
UIImageJPEGRepresentation(photo.image,70),#"file",
fldTitle.text, #"title",nil]
onCompletion:^(NSDictionary *json)
{
//completion
if (![json objectForKey:#"error"])
{
//success
[[[UIAlertView alloc]initWithTitle:#"Success!"
message:#"Your photo is uploaded"
delegate:nil cancelButtonTitle:#"Yay!"
otherButtonTitles: nil] show];
}
else
{
//error, check for expired session and if so - authorize the user
NSString* errorMsg = [json objectForKey:#"error"];
[UIAlertView error:errorMsg];
if ([#"Authorization required" compare:errorMsg]==NSOrderedSame)
{
[self performSegueWithIdentifier:#"ShowLogin" sender:nil];
}
}
}];
return YES;
}
What am I doing wrong?

You method needs to return a BOOL. In your method you should have the statement return YES; somewhere if the method succeeds and a return NO; if it fails. You can modify your code to the following:
PhotoScreen *script = [[PhotoScreen alloc] init];
if ([script uploadPhoto])
{
NSLog(#"Sucess!");
}
The repetitive method calls were unnecessary along with the comparison.

Related

Optimistic concurrency in Azre iOS client SDK

I have a query regarding concurrency in Azure mobile client SDK.
for windows I found Conflict link for handling concurrency but I could not found the same for iOS client SDK.
Can anyone please suggest or help how to handle concurrency in iOS client SDK.
Here is the old Mobile Services page for handling conflicts with the iOS SDK. The setup for offline sync with the iOS SDK hasn't changed since then.
1) Set up an MSSyncContextDelegate and pass it to the MSSyncContext constructor when you create it.
2) Implement tableOperation:(MSTableOperation *)operation onComplete:(MSSyncItemBlock)completion in your delegate. After executing the operation, check for an MSErrorPreconditionFailed error code and decide what to do from there based on your app's needs.
- (void)tableOperation:(MSTableOperation *)operation onComplete:(MSSyncItemBlock)completion
{
[operation executeWithCompletion:^(NSDictionary *item, NSError *error) {
NSDictionary *serverItem = [error.userInfo objectForKey:MSErrorServerItemKey];
if (error.code == MSErrorPreconditionFailed) {
QSUIAlertViewWithBlock *alert = [[QSUIAlertViewWithBlock alloc] initWithCallback:^(NSInteger buttonIndex) {
if (buttonIndex == 1) { // Client
NSMutableDictionary *adjustedItem = [operation.item mutableCopy];
[adjustedItem setValue:[serverItem objectForKey:MSSystemColumnVersion] forKey:MSSystemColumnVersion];
operation.item = adjustedItem;
[self doOperation:operation complete:completion];
return;
} else if (buttonIndex == 2) { // Server
NSDictionary *serverItem = [error.userInfo objectForKey:MSErrorServerItemKey];
completion(serverItem, nil);
} else { // Cancel
[operation cancelPush];
completion(nil, error);
}
}];
NSString *message = [NSString stringWithFormat:#"Client value: %#\nServer value: %#", operation.item[#"text"], serverItem[#"text"]];
[alert showAlertWithTitle:#"Server Conflict"
message:message
cancelButtonTitle:#"Cancel"
otherButtonTitles:[NSArray arrayWithObjects:#"Use Client", #"Use Server", nil]];
} else {
completion(item, error);
}
}];
}

CKAccountStatus returning different values when not called from ViewController

I'm using Cloud Kit in my app which makes use of the camera and only allows the user to submit photos if they're logged into iCloud. So when the user clicks the camera button, I call a CloudKit method to get the user's icloud status, which returns a CKAccountStatus value (0-3). I implemented this initially in the view controller and it worked perfectly. Then I did some refactoring and created a CKManager class to house all CK related methods. So now when the camera is clicked instead of calling the CK method off the container directly in the VC, I'm calling it via a method from my CKManager property (which is lazy instantiated). It should only return values 0-3, but it keeps returning 448 for some reason. However, in the CKManager logging, I can see it logging correctly that I'm logged into iCloud. So there's an issue of it translating from there back to the VC. I have feeling this is a threading/callback issue, which I'm not that well versed in.
Can someone take a look at the code and see if there's something obvious I'm doing wrong? Thanks in advance!
- (IBAction)cameraBarButtonPressed:(UIBarButtonItem *)sender {
NSLog(#"Entered cameraBarButtonPressed");
//CKContainer *container = [CKContainer defaultContainer];
dispatch_queue_t fetchQ = dispatch_queue_create("check user status", NULL);
__block CKAccountStatus userAccountStatus;
dispatch_async(fetchQ, ^{ // check user's CK status on different thread
userAccountStatus = [self.ckManager getUsersCKStatus];
NSLog(#"cameraBarButtonPressed userAccountStatus: %ld", userAccountStatus);
if (userAccountStatus == CKAccountStatusAvailable) {
//NSLog(#"User is logged into CK - user can upload pics!");
UIImagePickerController *cameraUI = [[UIImagePickerController alloc] init];
cameraUI.delegate = self; // set the deleage for the ImagePickerController
// check to see if the camera is available as source type, else check for photo album
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
cameraUI.sourceType = UIImagePickerControllerSourceTypeCamera;
} else if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeSavedPhotosAlbum]) {
cameraUI.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
}
[cameraUI setAllowsEditing:YES]; // let the user edit the photo
// set the camera presentation style
//cameraUI.modalPresentationStyle = UIModalPresentationFullScreen;
cameraUI.modalPresentationStyle = UIModalPresentationCurrentContext;
dispatch_async(dispatch_get_main_queue(), ^{ // show the camera on main thread to avoid latency
[self presentViewController:cameraUI animated:YES completion:nil]; // show the camera with animation
});
} else if (userAccountStatus == CKAccountStatusNoAccount) {
//NSLog(#"User is not logged into CK - Camera not available!");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"iCloud Not Available" message:#"You must be logged into your iCloud account to submit photos and recipes. Go into iCloud under Settings on your device to login." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
dispatch_async(dispatch_get_main_queue(), ^{
[alert show];
});
} else if (userAccountStatus == CKAccountStatusRestricted) {
NSLog(#"User CK account is RESTRICTED !");
} else if (userAccountStatus == CKAccountStatusCouldNotDetermine) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"iCloud Status Undetermined" message:#"We could not determine your iCloud status. You must be logged into your iCloud account to submit photos and recipes. Go into iCloud under Settings on your device to login." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
dispatch_async(dispatch_get_main_queue(), ^{
[alert show];
});
} else { // did not get back one of the above values so show the Could Not Determine message
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"iCloud Status Undetermined" message:#"We could not determine your iCloud status. You must be logged into your iCloud account to submit photos and recipes. Go into iCloud under Settings on your device to login." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
dispatch_async(dispatch_get_main_queue(), ^{
[alert show];
});
}
});
}
The above code is the code that does not work. Here is the code that does work. Just copying the beginning code as the rest is redundant from that point on...
CKContainer *container = [CKContainer defaultContainer];
dispatch_async(fetchQ, ^{ // check user's CK status on different thread
[container accountStatusWithCompletionHandler:^(CKAccountStatus accountStatus, NSError *error) {
if (error) {...
Lastly, here is the code that gets called from CKManager for the code that does not work...
- (CKAccountStatus)getUsersCKStatus {
NSLog(#"Entered getUsersCKStatus...");
__block CKAccountStatus userAccountStatus;
[self.container accountStatusWithCompletionHandler:^(CKAccountStatus accountStatus, NSError *error) {
if (error) {
NSLog(#"Error: Error encountered while getting user CloudKit status: %#", error.localizedDescription);
} else {
if (accountStatus == CKAccountStatusAvailable) {
NSLog(#"Info: User is logged into CK - camera is available!");
userAccountStatus = CKAccountStatusAvailable;
} else if (accountStatus == CKAccountStatusNoAccount) {
NSLog(#"Info: User is not logged into CK - Camera not available!");
userAccountStatus = CKAccountStatusNoAccount;
} else if (accountStatus == CKAccountStatusRestricted) {
NSLog(#"Info: User CK account is RESTRICTED - what does that mean!?");
userAccountStatus = CKAccountStatusRestricted;
} else if (accountStatus == CKAccountStatusCouldNotDetermine) {
NSLog(#"Error: Could not determine user CK Account Status: %#", error.localizedDescription);
userAccountStatus = CKAccountStatusCouldNotDetermine;
}
}
}];
NSLog(#"CKAccountStatus: %ld", userAccountStatus);
return userAccountStatus;
}
In the getUsersCKStatus you are calling the accountStatusWithCompletionHandler. That is an asynchronous method. In your case it will return the userAccountStatus before it is set by its callback method.
You could solve this by making that method synchronous by implementing a semaphore. A better way would be passing on a callback block to that method and not returning a value.

how to check bool value before going for fast app switch using FBLoginView

Here is a simple scenario, I am using FBLoginView which show a login button and on click application go for fast switching but i want to check a bool value of terms and conditions before app go for fast switch. There is not way i am able to find to achieve this scenario.
- (void)loginViewShowingLoggedInUser:(FBLoginView *)loginView {
// Upon login, transition to the main UI by pushing it onto the navigation stack.
LGAppDelegate *appDelegate = (LGAppDelegate *)[UIApplication sharedApplication].delegate;
[self.navigationController pushViewController:((UIViewController *)appDelegate.mainViewController) animated:YES];
}
- (void)acceptTermsAndConditions {
if (!_checkboxButton.checked) {
NSString *alertMessage, *alertTitle;
alertTitle = #"Terms to Use";
alertMessage = #"Please accept the terms & condition to use this application.";
UIAlertView* av = [[UIAlertView alloc] initWithTitle:alertTitle
message:alertMessage
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[av show];
[av release];
}
}
- (void)loginView:(FBLoginView *)loginView
handleError:(NSError *)error{
NSString *alertMessage, *alertTitle;
// Facebook SDK * error handling *
// Error handling is an important part of providing a good user experience.
// Since this sample uses the FBLoginView, this delegate will respond to
// login failures, or other failures that have closed the session (such
// as a token becoming invalid). Please see the [- postOpenGraphAction:]
// and [- requestPermissionAndPost] on `SCViewController` for further
// error handling on other operations.
if (error.fberrorShouldNotifyUser) {
// If the SDK has a message for the user, surface it. This conveniently
// handles cases like password change or iOS6 app slider state.
alertTitle = #"Something Went Wrong";
alertMessage = error.fberrorUserMessage;
} else if (error.fberrorCategory == FBErrorCategoryAuthenticationReopenSession) {
// It is important to handle session closures as mentioned. You can inspect
// the error for more context but this sample generically notifies the user.
alertTitle = #"Session Error";
alertMessage = #"Your current session is no longer valid. Please log in again.";
} else if (error.fberrorCategory == FBErrorCategoryUserCancelled) {
// The user has cancelled a login. You can inspect the error
// for more context. For this sample, we will simply ignore it.
NSLog(#"user cancelled login");
} else {
// For simplicity, this sample treats other errors blindly, but you should
// refer to https://developers.facebook.com/docs/technical-guides/iossdk/errors/ for more information.
alertTitle = #"Unknown Error";
alertMessage = #"Error. Please try again later.";
NSLog(#"Unexpected error:%#", error);
}
if (alertMessage) {
[[[UIAlertView alloc] initWithTitle:alertTitle
message:alertMessage
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil] show];
}
}
- (void)loginViewShowingLoggedOutUser:(FBLoginView *)loginView {
// Facebook SDK * login flow *
// It is important to always handle session closure because it can happen
// externally; for example, if the current session's access token becomes
// invalid. For this sample, we simply pop back to the landing page.
LGAppDelegate *appDelegate = (LGAppDelegate *)[UIApplication sharedApplication].delegate;
if (appDelegate.isNavigating) {
// The delay is for the edge case where a session is immediately closed after
// logging in and our navigation controller is still animating a push.
[self performSelector:#selector(logOut) withObject:nil afterDelay:.5];
} else {
[self logOut];
}
}
- (void)logOut {
[self.navigationController popToRootViewControllerAnimated:YES];
}

Display a loading indicator after user taps "Share" and before request is completed?

The issue I have is that after users tap on the "Share" button of the FBDialog, they do not get any visual feedback until the request completes or fail... and over 3G that can takes a while. During this time users do not know if they tapped "Share" correctly or not, and there's risk of posting content twice.
Is there a way I can get a callback so I can display a loading indicator during this time? Where should I put this piece in?
Thank you!
Below code you write to fbAgent.m and also obser code here u get one "PID" at that time u write to alert msg ....... user can understand to that msg was success posted Facebook.
I hope this helps.
- (void)request:(FBRequest*)request didLoad:(id)result {
if ([request.method isEqualToString:#"facebook.fql.query"]) {
NSArray* users = result;
NSDictionary* user = [users objectAtIndex:0];
NSString* name = [user objectForKey:#"name"];
// Calling the delegate callback
[delegate facebookAgent:self didLoadName:name];
} else if ([request.method isEqualToString:#"facebook.users.setStatus"]) {
newStatus = nil;
NSString* success = result;
if ([success isEqualToString:#"1"]) {
// Calling the delegate callback
[delegate facebookAgent:self statusChanged:YES];
} else {
[delegate facebookAgent:self statusChanged:NO];
}
} else if ([request.method isEqualToString:#"facebook.photos.upload"]) {
NSDictionary* photoInfo = result;
NSString* pid = [photoInfo objectForKey:#"pid"];
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:nil message:[NSString stringWithFormat:#"success Uploaded Your image please check your FaceBook", pid] delegate:self cancelButtonTitle:nil otherButtonTitles:#"Ok", nil];
[alertView show];
[alertView release];
fbbut.enabled=YES;
[fbact stopAnimating];
self.uploadImageData = nil;
self.uploadImageCaption = nil;
self.uploadImageAlbum = nil;
//[delegate facebookAgent:self photoUploaded:pid];
if(newStatus){
[self setStatus:newStatus];
}
}
}
Start your indicator when you click on button and stop on Delegate of Facebook function
- (void)dialogDidComplete:(FBDialog *)dialog
Hope it helps....

xcode iOS compare strings

How do i compare a website result with a predicted result.
#"document.getElementsByTagName('body')[0].outerHTML"
is predicted to contain:
<body>OK</body>
But i always get an error saying that they don't match. I used this code below to compare them:
if (webresult == cmp){
then it shows an alert saying success. Or in else it'll say error. It always goes to else. Heres the code block, Please help.
- (IBAction)displayresult:(id)sender {
webresult = [webview2 stringByEvaluatingJavaScriptFromString:#"document.getElementsByTagName('body')[0].outerHTML"];
NSString *cmp = [[NSString alloc] initWithFormat:#"<body>OK</body>"];
if (webresult == cmp) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Logged in" message:#"Logged in, Proceeding to the game" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:webresult delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
}
I assume that webresult is an NSString. If that is the case, then you want to use:
if ([webresult isEqualToString:cmp]) {
instead of:
if (webresult == cmp) {
as the above method checks if the strings are equal character by character, whereas the bottom method checks if the two strings are the same pointer.
if (webresult == cmp)
Here, == checks whether webresult, cmp are pointing to the same reference or not. You should instead compare value of the object by using NSString::isEqualToString.
if ( [ cmp isEqualToString:webresult ]) {
// ..
}else {
// ..
}
Note that isEqualToString is a good option because it returns boolean value.
We cannot comapre the strings with ==
We have to use isEqualToString:
if([str1 isEqualToString:str2])
{
}
else
{
}
When comparing strings you need to use isEqualToString:
if ([cmp isEqualToString:webresult]) {
...
} else {
...
}
for Swift 4.0:
if str1==str2 {
//both string are equal
}
else {
//do something expression not true
}
for Objective-C:
if ([str1 isEqualToString:str2]) {
//both string are equal
}
else {
//do something expression not true
}

Resources