I seem to have trouble understanding how to best deal with the BFTask (Bolts framework) return object for several AWS SDK iOS v2 methods. I am trying to get the name of the region my bucket resides in. Could anyone suggest how to do that given the locationConstraint information I am successfully receiving from the following code? Or is there a generic way to understand what the task.result object contains?
AWSS3TransferManagerUploadRequest *uploadRequest = [AWSS3TransferManagerUploadRequest new];
AWSS3 *myS3 = [[AWSS3 alloc] initWithConfiguration:self.configurationS3];
AWSS3GetBucketLocationRequest *locReq = [AWSS3GetBucketLocationRequest new];
locReq.bucket=#"testAWS";
[[myS3 getBucketLocation:locReq] continueWithExecutor:[BFExecutor mainThreadExecutor] withBlock:^id(BFTask *task) {
if(task.error != nil){
NSLog(#"%s Location not found: [%#]",__PRETTY_FUNCTION__, task.error);
} else {
NSLog(#"Location found: [%#] - %li", task.result, [task.result locationConstraint]);
}
return nil;
}];
Also, if anyone has suggestions for tutorials/examples for best understanding BFTask that would be helpful. Thanks for your help. Cheers, Trond
ps. I also asked this question on AWS support site.
Here is the code snippet to determine the bucket location:
AWSS3 *s3 = [AWSS3 defaultS3];
AWSS3GetBucketLocationRequest *getBucketLocationRequest = [AWSS3GetBucketLocationRequest new];
getBucketLocationRequest.bucket = testBucketNameGeneral;
[[s3 getBucketLocation:getBucketLocationRequest] continueWithBlock:^id(BFTask *task) {
if(task.error != nil){
XCTAssertNil(task.error, #"The request failed. error: [%#]", task.error);
}
AWSS3GetBucketLocationOutput *getBucketLocationOutput = task.result;
XCTAssertEqual(getBucketLocationOutput.locationConstraint, AWSS3BucketLocationConstraintBlank);
switch (getBucketLocationOutput.locationConstraint) {
case AWSS3BucketLocationConstraintBlank:
NSLog(#"Classic Region");
break;
case AWSS3BucketLocationConstraintEU:
NSLog(#"EU");
break;
case AWSS3BucketLocationConstraintEUWest1:
NSLog(#"eu-west-1");
break;
case AWSS3BucketLocationConstraintUSWest1:
NSLog(#"us-west-1");
break;
case AWSS3BucketLocationConstraintUSWest2:
NSLog(#"us-west-2");
break;
case AWSS3BucketLocationConstraintAPSoutheast1:
NSLog(#"ap-southeast-1");
break;
case AWSS3BucketLocationConstraintAPSoutheast2:
NSLog(#"ap-southeast-2");
break;
case AWSS3BucketLocationConstraintAPNortheast1:
NSLog(#"ap-northeast-1");
case AWSS3BucketLocationConstraintSAEast1:
NSLog(#"sa-east-1");
break;
case AWSS3BucketLocationConstraintUnknown:
default:
// Error
break;
}
return nil;
}];
However, there is a bug in the SDK, and getBucketLocationOutput.locationConstraint is always AWSS3BucketLocationConstraintUnknown. We are working on the fix right now.
The Bolts-iOS GitHub repo has a pretty good instructions on how to use Bolts.
Hope this helps,
Update
The AWS Mobile SDK for iOS 2.0.4 has been released. The update fixes the issue, and now it returns the correct locationConstraint.
Related
I'm using this method to upload images/videos to S3 (see code below)
I'm wondering if a user backgrounds the app and much later opens it back up can the pause/resume be used to resume all those uploads? It looks like maybe it's persistently caching the uploads in the SDK with self.cache.diskCache. In other words can I use a UIBackgroundTask to pause the downloads in the expiration handler and when the app comes back in the foreground resumeAll?
I was watching this talk on how to do persistent uploads with NSURLSession and am trying to design a good way to do it in my current app.
Something like this:
- (void)applicationWillEnterForeground:(NSNotification *)notification
{
[self.transferManager resumeAll:^(AWSRequest *request) {
POLYLog(#"request %#",request.description);
}];
}
- (void)applicationDidEnterBackground:(NSNotification *)notification
{
UIApplication* app = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier task;
task = [app beginBackgroundTaskWithExpirationHandler:^{
[self.transferManager pauseAll];
[app endBackgroundTask:task];
task = UIBackgroundTaskInvalid;
}];
}
Reference from AWS Docs:
// Construct the NSURL for the download location.
NSString *downloadingFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:#"downloaded-myImage.jpg"];
NSURL *downloadingFileURL = [NSURL fileURLWithPath:downloadingFilePath];
// Construct the download request.
AWSS3TransferManagerDownloadRequest *downloadRequest = [AWSS3TransferManagerDownloadRequest new];
downloadRequest.bucket = #"myBucket";
downloadRequest.key = #"myImage.jpg";
downloadRequest.downloadingFileURL = downloadingFileURL;
Now we can pass the download request to the download: method of the TransferManager client. The AWS Mobile SDK for iOS uses AWSTask to support asynchronous calls to Amazon Web Services. The download: method is asynchronous and returns a AWSTask object, so we’ll use it accordingly:
[[transferManager upload:uploadRequest] continueWithExecutor:[AWSExecutor mainThreadExecutor]
withBlock:^id(AWSTask *task) {
if (task.error) {
if ([task.error.domain isEqualToString:AWSS3TransferManagerErrorDomain]) {
switch (task.error.code) {
case AWSS3TransferManagerErrorCancelled:
case AWSS3TransferManagerErrorPaused:
break;
default:
NSLog(#"Error: %#", task.error);
break;
}
} else {
// Unknown error.
NSLog(#"Error: %#", task.error);
}
}
if (task.result) {
AWSS3TransferManagerUploadOutput *uploadOutput = task.result;
// The file uploaded successfully.
}
return nil;
}];
I am developing an chat app where I transfer media like videos / audio/ images.
When the transfer is done with below code snippet, the transfer is smooth on Wifi but is very very slow when moved to 3G network.
Also another issue is when I go in background the AWS SDK pause the transfer and resumes when I come in foreground.
1) How can I make the transfer fast as I have tried changing the AWS region still no success.
2) Also use the S3Background transfer example compared to AWS S3 transfer manager used but the download paused when I press home button.
Below is my code snipped.
//Upload function
AWSS3TransferManager *transferManager = [AWSS3TransferManager defaultS3TransferManager];
AWSS3TransferManagerUploadRequest *uploadRequest = [AWSS3TransferManagerUploadRequest new];
uploadRequest.bucket = S3BucketName;
User *userMO = .....my user details
NSString *fileName = [[filePath componentsSeparatedByString:#"/"] lastObject];
uploadRequest.key = [userMO.user_pool_id stringByAppendingPathComponent:fileName];
NSURL *uploadFileURL = [NSURL fileURLWithPath:filePath];
uploadRequest.body = uploadFileURL;
uploadRequest.expires = [NSDate dateWithTimeIntervalSinceNow:3600];
NSString *fileContentTypeStr = #"image/jpg";
if ([FileManager isVideoFile:fileName]) {
// fileContentTypeStr = [NSString stringWithFormat:#"video/%#",[[fileName pathExtension] lowercaseString]];
fileContentTypeStr = [NSString stringWithFormat:#"video/quicktime"];
}
else if ([FileManager isImageFile:fileName]) {
fileContentTypeStr = [NSString stringWithFormat:#"image/%#",[[fileName pathExtension] lowercaseString]];
}
else if ([FileManager isAudioFile:fileName]) {
fileContentTypeStr = [NSString stringWithFormat:#"audio/%#",[[fileName pathExtension] lowercaseString]];
}
uploadRequest.contentType = fileContentTypeStr;
[[transferManager upload:uploadRequest] continueWithBlock:^id(AWSTask *task) {
if (task.error) {
if ([task.error.domain isEqualToString:AWSS3TransferManagerErrorDomain]) {
switch (task.error.code) {
case AWSS3TransferManagerErrorCancelled:
{
//updating ui to notify cancel
}
break;
case AWSS3TransferManagerErrorPaused:
{
//updating ui to notify paused
}
break;
default:
{
NSLog(#"Upload task failed: %#",[task.error localizedDescription]);
//updating ui to notify failed
}
break;
}
} else {
NSLog(#"Upload task failed: %#",[task.error localizedDescription]);
//updating ui to notify failed
}
}
if (task.result)
{
//updating ui to notify finished
}
return nil;
}];
if(uploadRequest.state == AWSS3TransferManagerRequestStateRunning)
{
//updating ui to notify progress
}
//Add the request to the current upload cache handler entry as handle
Any body have any suggestions and faced similar issue.
Use AWS background transfer not AWS transfer manager to use the background mode supported transfer.
I'm not found simple solution for this question on SO.
I need simple check logic for my URL and return YES - if available or NO - if not.
What i found:
-(BOOL)connectedToNetwork {
NSURL* url = [[NSURL alloc] initWithString:#"http://google.com/"];
NSData* data = [NSData dataWithContentsOfURL:url];
if (data != nil)
return YES;
return NO;
}
founded this
But i need more correctly answer.
UPD
I found SimplePing by Apple.
UPD1
Found answer on SO Thx all!
UPD2
Better solution SimplePingHelper required SimplePing:
- (void)tapPing {
[SimplePingHelper ping:#"www.google.com"
target:self sel:#selector(pingResult:)];
}
- (void)pingResult:(NSNumber*)success {
if (success.boolValue) {
[self log:#"SUCCESS"];
} else {
[self log:#"FAILURE"];
}
}
The preferred approach is trying to connect, and if that fails due to the host is not reachable check and monitor the network state. See Reachability. If the network state indicates that a host can be possibly reached, try again.
There are also a couple of third party libs that implement a handy API over Apple's Reachability interface.
I use AFNetworking to check reachability.
Pod file: pod "AFNetworking"
You have to include AFNetworkReachabilityManager.h in the file you want to use it.
This is a sample, basic code to check reachability.
// -- Start monitoring network reachability (globally available) -- //
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
NSLog(#"Reachability changed: %#", AFStringFromNetworkReachabilityStatus(status));
switch (status) {
case AFNetworkReachabilityStatusReachableViaWWAN:
case AFNetworkReachabilityStatusReachableViaWiFi:
// -- Reachable -- //
NSLog(#"Reachable");
break;
case AFNetworkReachabilityStatusNotReachable:
default:
// -- Not reachable -- //
NSLog(#"Not Reachable");
break;
}
}];
A valid URL is made of these characters :
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]#!$&'()*+,;=
You simply need to make a String checking function to validate your URL's characters are falling in or out.
Its was simple:
-(BOOL)connectedToNetwork {
NSURL* url = [[NSURL alloc] initWithString:#"http://google.com/"];
NSData* data = [NSData dataWithContentsOfURL:url];
if (data != nil)
return YES;
return NO;
}
founded this
Its the first time i use unibill for my ios game and i got an issue when i try to build and run my app onto the device.
I get the message, that there is a use of undeclared idenifier for the case SKPaymentTransactionStateDeferred: (i didnt changed anything on the unibill plugin sourcecode) so iam not sure what to do.
i cant post an image so i post the code below. Pls watch on the line XCODE ISSUE.
// The transaction status of the SKPaymentQueue is sent here.
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray*)transactions {
NSLog(#"Unibill: updatedTransactions");
for(SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
// Item is still in the process of being purchased
break;
case SKPaymentTransactionStatePurchased:
case SKPaymentTransactionStateRestored: {
// Item was successfully purchased or restored.
NSMutableDictionary* dic;
dic = [[NSMutableDictionary alloc] init];
[dic setObject:transaction.payment.productIdentifier forKey:#"productId"];
[dic setObject:[self selectReceipt:transaction] forKey:#"receipt"];
NSData* data;
data = [NSJSONSerialization dataWithJSONObject:dic options:0 error:nil];
NSString* result;
result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
UnitySendMessage(UNITY_GAMEOBJECT_NAME, "onProductPurchaseSuccess", result.UTF8String);
#if !__has_feature(objc_arc)
[result release];
[dic release];
#endif
// After customer has successfully received purchased content,
// remove the finished transaction from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
break;
}
case SKPaymentTransactionStateDeferred:
**//XCODE ISSUE: USE OF UNDECLARED IDENTIFIER "SKPaymentTransactionStateDeferred"**
NSLog(#"Unibill: purchaseDeferred");
UnitySendMessage(UNITY_GAMEOBJECT_NAME, "onProductPurchaseDeferred", transaction.payment.productIdentifier.UTF8String);
break;
case SKPaymentTransactionStateFailed:
// Purchase was either cancelled by user or an error occurred.
NSString* errorCode = [NSString stringWithFormat:#"%d",transaction.error.code];
if (transaction.error.code != SKErrorPaymentCancelled) {
NSLog(#"Unibill: purchaseFailed: %#", errorCode);
UnitySendMessage(UNITY_GAMEOBJECT_NAME, "onProductPurchaseFailed", transaction.payment.productIdentifier.UTF8String);
} else {
NSLog(#"Unibill: purchaseFailed: %#", errorCode);
UnitySendMessage(UNITY_GAMEOBJECT_NAME, "onProductPurchaseCancelled", transaction.payment.productIdentifier.UTF8String);
}
// Finished transactions should be removed from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
break;
}
}
}
does someone know what i should do? another question: where can i find the declaration of the cases called in the unibillstorekit.mm file? Or where do i have to declare this identifier?
please tell me if you need more specific informations.
note: iam just a beginner :)
Have you changed your deployment target?
The problem can be due to your deployment target pointing to iOS version below 8.0. SKPaymentTransactionStateDeferred is only available in iOS version greater to 8. So if your deployment target is set to e.g. 7.1 you'll run into this error.
To get rid of this you can just update your deployment target to be greater or equal to 8.0 or use another (older) version of the library or plugin, repsectively
Hope this helps.
I'm very new to backend programming and iOS programming. I'm currently integrating DynamoDB into my iOS application. I'm doing a signup function that queries the database to check whether the username is taken.
Here's the main idea of my code:
__block BOOL isPlayerTaken = NO;
//Block of code that queries the database
//Mutates value of isPlayerTaken if player exists
[[dynamoDBObjectMapper query:[DDBRunnerTableRow class]
expression:queryExpression]
continueWithExecutor:[BFExecutor mainThreadExecutor] withSuccessBlock:^id(BFTask *task) {
AWSDynamoDBPaginatedOutput *paginatedOutput = task.result;
DDBRunnerTableRow *queriedRunner = paginatedOutput.items[0];
if (queriedRunner) {
isPlayerTaken = YES;
NSLog(#"%#", queriedRunner.runnerName);
}
return nil;
}];
return isPlayerTaken;
However, the function returns before the query result is completed and hence the output is always NO.
How can I ensure that the function doesn't return until the query block completes?
Thank you so much for your help. I believe I would need this in many functions of my code that requires querying and inserting of data and I didn't want to come up with a hackish solution for it.
Try something like this:
[[dynamoDBObjectMapper query:[DDBRunnerTableRow class]
expression:queryExpression]
continueWithExecutor:[BFExecutor mainThreadExecutor] withSuccessBlock:^id(BFTask *task) {
AWSDynamoDBPaginatedOutput *paginatedOutput = task.result;
DDBRunnerTableRow *queriedRunner = paginatedOutput.items[0];
if (queriedRunner)
{
NSLog(#"%#", queriedRunner.runnerName);
[self loginSuccessfull:queriedRunner];
}
else
{
[self loginFailed];
}
}];
then
- (void)loginSuccessfull:(DDBRunnerTableRow *)queriedRunner
{
//whatever
}
- (void)loginFailed
{
//whatever
}