S3TransferManager not able to save file/data on S3GetObjectRequest targetedFilePath in ios - ios

I am an iOS developer using Amazon S3 to upload and download the data. I successfully uploaded many image files, but when I am trying to download those all files, I am not able to save data or file on targeted path of S3GetObjectRequest. I am requesting object through the S3TransferManager.
Below is my code
- (void)listObjects:(id)sender {
self.collection = [[NSMutableArray alloc] init];
s3Client = [[AmazonS3Client alloc] initWithAccessKey:ACCESS_KEY_ID withSecretKey:SECRET_KEY];
#try {
S3ListObjectsRequest *req = [[S3ListObjectsRequest alloc] initWithName:AMAZON_BUCKET_NAME];
req.prefix = #"arvinds/8/";
//req.prefix = [NSString stringWithFormat:#"%#", self.appUser.userEmail];
S3ListObjectsResponse *resp = [s3Client listObjects:req];
NSMutableArray* objectSummaries = resp.listObjectsResult.objectSummaries;
for (int x = 0; x < [objectSummaries count]; x++) {
NSLog(#"objectSummaries: %#",[objectSummaries objectAtIndex:x]);
S3ObjectSummary *s3Object = [objectSummaries objectAtIndex:x];
NSString *downloadingFilePath = [[NSTemporaryDirectory() stringByAppendingPathComponent:#"download"] stringByAppendingPathComponent:s3Object.key];
NSURL *downloadingFileURL = [NSURL fileURLWithPath:downloadingFilePath];
NSLog(#"downloadingFilePath--- %#",downloadingFilePath);
if ([[NSFileManager defaultManager] fileExistsAtPath:downloadingFilePath]) {
[self.collection addObject:downloadingFileURL];
} else {
[self.collection addObject:downloadingFileURL];
S3GetObjectRequest *getObj = [[S3GetObjectRequest new] initWithKey:s3Object.key withBucket:AMAZON_BUCKET_NAME];
getObj.targetFilePath = downloadingFilePath;
getObj.delegate = self;
[self download:getObj];// Start downloding image and write in default folder
}
}
dispatch_async(dispatch_get_main_queue(), ^{
[self.GalleryCollectionView reloadData];
//[self downloadAllRequestObject];
});
}
#catch (NSException *exception) {
NSLog(#"Cannot list S3 %#",exception);
}
}
// Above code is for access all the objects stored on Amazon S3 server.
// Below code is for S3TransferManager request
- (void)download:(S3GetObjectRequest *)downloadRequest {
S3TransferManager *transferManager = [S3TransferManager new];
transferManager.s3 = s3Client;
transferManager.delegate = self;
[transferManager download:downloadRequest];
}
When executing this, it is not saving data on the target path.

- download: is an asynchronous method and returns immediately. Since you are not retaining a strong reference to an instance of S3TransferManager, it can be released before the download completes. You need to keep a strong reference to transferManager.
Please note that you are using a deprecated version of the AWS SDK. It may be worthwhile to migrate to the version 2 of the AWS Mobile SDK for iOS. With the latest version of the SDK, you do not need to worry about the memory retention issue you are encountering.

Related

Amazon s3 transfer utility not working in background

i have to upload a large file like more then 4gb onto amazon s3. amazon sdk giving two options for uploading and downloading from s3. one is awss3transfermanager and other is awss3transferutility. i actually want to use awss3transferutility because i want the app to continue uploading in background. awss3transferutility has two functions uploadFile and other uploadFileUsingMultiPart . uploadFile function actually works in background but uploading starts from 0 on network changes or drop. For that reason i am curretly using uploadFileUsingMultiPart function so the uploading won't get restart from 0 on networks fail. but this uploadFileUsingMultiPart function won't continue uploading in background. In their latest release they introduce this uploadFileUsingMultiPart function inside awstransferutility. so i was expecting that uploading will continue in background with network fail but it won't continue in background. i just wanted to ask is it sdk related bug or i am doing something wrong
this is the code i am curretly
//in app delegate
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler {
[AWSS3TransferUtility interceptApplication:application
handleEventsForBackgroundURLSession:identifier
completionHandler:completionHandler];
}
// in ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reachabilityChanged:)
name:kReachabilityChangedNotification
object:nil];
__weak typeof(self) weakSelf = self;
expression = [AWSS3TransferUtilityMultiPartUploadExpression new];
expression.progressBlock = ^(AWSS3TransferUtilityMultiPartUploadTask * task, NSProgress * progress) {
typeof(self) newWeakSelf = weakSelf;
dispatch_async(dispatch_get_main_queue(), ^{
// Do something e.g. Alert a user for transfer completion.
NSLog(#"progress value %f",progress.fractionCompleted);
// On failed uploads, `error` contains the error object.
newWeakSelf->progressView.progress = progress.fractionCompleted;
});
};
completionHandler = ^(AWSS3TransferUtilityMultiPartUploadTask *task, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"uploading completed ");
});
};
AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionUSEast1 identityPoolId:#"us-west-1:7a24b199-e4b2-4657-9627-sdfs4ssdff"];
AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1 credentialsProvider:credentialsProvider];
// AWSServiceManager.defaultServiceManager.defaultServiceConfiguration = configuration;
AWSS3TransferUtilityConfiguration *tfConfig = [AWSS3TransferUtilityConfiguration new];
tfConfig.retryLimit = 5;
tfConfig.multiPartConcurrencyLimit = [NSNumber numberWithInteger:3];
[AWSS3TransferUtility registerS3TransferUtilityWithConfiguration:configuration transferUtilityConfiguration:tfConfig forKey:#"transfer-utility-with-advanced-options"];
transferUtility = [AWSS3TransferUtility S3TransferUtilityForKey:#"transfer-utility-with-advanced-options"];
}
-(void)startUploading {
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"test" ofType:#"mp4"];
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
NSString *fileContentTypeStr = #"video/mp4";
// NSData *data = [NSData dataWithContentsOfURL:fileURL];
// AWSTask *task = [transferUtility uploadDataUsingMultiPart:data bucket:#"sibme-development" key:#"temp/testfilenew/testfile1.mp4" contentType:fileContentTypeStr expression:expression completionHandler:completionHandler ];
AWSTask *task = [transferUtility uploadFileUsingMultiPart:fileURL bucket:#"development" key:#"temp/testfilenew/testfile.mp4" contentType:fileContentTypeStr expression:expression completionHandler:completionHandler];
[task continueWithBlock:^id _Nullable(AWSTask * _Nonnull t) {
if (t.result) {
self->uplaodTask = t.result;
}
return nil;
}];
}
I am not expert on this, but I noticed something in your code - Bucket region:
initWithRegionType:AWSRegionUSEast1
identityPoolId:#"us-west-1:...
Once I had similar mismatch in my code, the bucket region and the Cognito identity pool region did not match, and that was causing problems. This may or may not be the case in your code, but just adding some info based on my experience.
AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionUSEast1 identityPoolId:#"us-west-1:7a24b199-e4b2-4657-9627-sdfs4ssdff"];
AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1 credentialsProvider:credentialsProvider];
If you think there is a bug with the SDK, you can try with the latest version of the SDK and if you are still seeing issues, open an Issue over in https://github.com/aws-amplify/aws-sdk-ios with some repro steps.

How to wait for delegate method execution before return statement?

I have a model object that has a class method that checks if the model object already exists, and if it does it returns it, or if it doesn't it creates it and then returns it. This class makes use of the VLC framework for generating data about video files and to generate a thumbnail. This is where I'm having trouble.
The VLCThumbnailer returns the thumbnail via a delegate method once it's fetchthumbnail method is called. The problem is that the delegate method doesn't get returned until AFTER my class-creation method reaches it's return function. Here's a code example.
-(AnimuProfile*)createnewProfileforFilename:(NSString*)filename{
NSURL *fileURL = [NSURL fileURLWithPath:filename];
VLCMedia *media = [VLCMedia mediaWithURL:fileURL];
FilenameParser *parser = [[FilenameParser alloc]init];
NSArray *parsedFilename = [parser parseFilename:[filename lastPathComponent]];
NSArray *mediaArray = [media tracksInformation];
if (mediaArray.count != 0) {
NSDictionary *videoTrackinfo = [mediaArray objectAtIndex:0];
_fansubGroup = parsedFilename[0];
_seriesTitle = parsedFilename[1];
_episodeNumber = parsedFilename[2];
_filename = [filename lastPathComponent];
_filepathURL = fileURL;
_filepathString = filename;
_watched = NO;
_progress = [VLCTime timeWithInt:0];
_length = [[media length]stringValue];
NSNumber *resolution = [videoTrackinfo valueForKey:#"height"];
_resolution = [NSString stringWithFormat:#"%#p",resolution];
VLCMediaThumbnailer *thumbnailer = [VLCMediaThumbnailer thumbnailerWithMedia:media andDelegate:self];
[thumbnailer fetchThumbnail];
NSString *libPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *profileName = [[_filename lastPathComponent] stringByAppendingPathExtension:#"prf"];
NSString *pathandProfileName = [libPath stringByAppendingPathComponent:profileName];
[NSKeyedArchiver archiveRootObject:self toFile:pathandProfileName];
return self;
}
And then the delegate methods:
#pragma mark VLC Thumbnailer delegate methods
- (void)mediaThumbnailerDidTimeOut:(VLCMediaThumbnailer *)mediaThumbnailerP{
NSLog(#"Thumbnailer timed out on file %#",_filename);
UIImage *filmstrip = [UIImage imageNamed:#"filmstrip"];
_thumbnail = UIImagePNGRepresentation(filmstrip);
}
- (void)mediaThumbnailer:(VLCMediaThumbnailer *)mediaThumbnailer didFinishThumbnail:(CGImageRef)thumbnail{
UIImage *image = [UIImage imageWithCGImage:thumbnail];
_thumbnail = UIImagePNGRepresentation(image);
}
I know it's a nono to lock the main thread waiting for the delegate method to be called so what should be done in this instance?
I know it's a nono to lock the main thread waiting for the delegate
method to be called so what should be done in this instance?
Those delegate methods are being called on VLC's video processing thread. They aren't the main thread and, therefore, you shouldn't be calling random UIKit API directly in the return blocks.
You need to process the results when they are available. If VLC were implemented using modern patterns, it would be using completion blocks. But it isn't, so...
- (void)mediaThumbnailer:(VLCMediaThumbnailer *)mediaThumbnailer didFinishThumbnail:(CGImageRef)thumbnail{
{
dispatch_async(dispatch_get_main_queue(), ^{ ... process thumbnail and update UI accordingly here ...});
}
That is, your createnewProfileforFilename: method should start the processing, but not expect it to be finished until sometime later. Then, when that sometime later happens, you trigger the updating of the UI with the data that was processed in the background.
And, as you state, you should never block the main queue/thread.
I was able to solve it by creating a separate class to be the delgate, make thumbnail fetch requests and then handle them.
#property NSMutableArray *queue;
#end
#implementation ThumbnailWaiter
+(id)sharedThumbnailWaiter{
static ThumbnailWaiter *singletonInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singletonInstance = [[self alloc] init];
});
return singletonInstance;
}
-(id)init{
self = [super init];
if (self) {
NSMutableArray *queue = [NSMutableArray array];
_queue = queue;
}
return self;
}
-(void)requestThumbnailForProfile:(AnimuProfile*)profile{
VLCMedia *media = [VLCMedia mediaWithURL:profile.filepathURL];
VLCMediaThumbnailer *thumbnailer = [VLCMediaThumbnailer thumbnailerWithMedia:media andDelegate:self];
[_queue addObject:profile];
[thumbnailer fetchThumbnail];
}
#pragma mark VLC Thumbnailer delegate methods
- (void)mediaThumbnailerDidTimeOut:(VLCMediaThumbnailer *)mediaThumbnailerP{
}
- (void)mediaThumbnailer:(VLCMediaThumbnailer *)mediaThumbnailer didFinishThumbnail:(CGImageRef)thumbnail{
UIImage *image = [UIImage imageWithCGImage:thumbnail];
AnimuProfile *profile = _queue.firstObject;
profile.thumbnail = UIImagePNGRepresentation(image);
[profile saveProfile];
[_queue removeObjectAtIndex:0];
}
Seems almost silly to have to do it this way but it seems to be working.

Uploading images to Firebase

I'm trying to upload images to Firebase like this:
Firebase *ref = [[Firebase alloc] initWithUrl:#"https://<app-name>.firebaseio.com/posts"];
Firebase *newPost = [ref childByAutoId];
NSDictionary *newPostData = #{
#"image" : [self encodeToBase64String:image]
};
[newPost updateChildValues:newPostData];
I'm using this code to encode the image:
- (NSString *)encodeToBase64String:(UIImage *)image {
return [UIImagePNGRepresentation(image) base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
}
But this does not work as the string exceeds the maximum size:
Terminating app due to uncaught exception 'InvalidFirebaseData', reason: '(updateChildValues:) String exceeds max size of 10485760 utf8 bytes:
What can I do to resolve this problem? I haven't found anything online in regards to iOS development and images when using Firebase.
If the image is too big, you should store a smaller image. Let me quote myself: How do you save a file to a Firebase Hosting folder location for images through android?
The Firebase Database allows you to store JSON data. While binary data is not a type that is supported in JSON, it is possible to encode the binary data in say base64 and thus store the image in a (large) string. [But] while this is possible, it is not recommended for anything but small images or as a curiosity to see that it can be done.
Your best option is typically to store the images on a 3rd party image storage service.
As Frank van Puffelen suggested, my solution was to use Amazon S3 for imagine storage, and use Firebase to store a reference to the image location.
I created a method called uploadImage: and it looks like this:
-(void)uploadImage:(UIImage *)image
{
// Create reference to Firebase
Firebase *ref = [[Firebase alloc] initWithUrl:#"https://<MY-APP>.firebaseio.com"];
Firebase *photosRef = [ref childByAppendingPath:#“photos];
Firebase *newPhotoRef = [photosRef childByAutoId];
// Image information
NSString imageId = [[NSUUID UUID] UUIDString];
// Create dictionary containing information
NSDictionary photoInformation = #{
#“photo_id” : imageId
// Here you can add more information about the photo
};
NSString *imagePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.png", imageId]];
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:imagePath atomically:YES];
NSURL *imageUrl = [[NSURL alloc] initFileURLWithPath:imagePath];
AWSS3TransferManagerUploadRequest *uploadRequest = [AWSS3TransferManagerUploadRequest new];
uploadRequest.bucket = #“<AMAZON S3 STORAGE NAME>“; // create your own by setting up an account on Amazon aws.
uploadRequest.key = imageId;
uploadRequest.contentType = #"image/png";
uploadRequest.body = imageUrl;
AWSS3TransferManager *transferManager = [AWSS3TransferManager defaultS3TransferManager];
[[transferManager upload:uploadRequest] continueWithExecutor:[AWSExecutor mainThreadExecutor] withBlock:^id(AWSTask *task) {
if (!task.error) {
// Update Firebase with reference
[newPhotoRef updateChildValues:currentPHD withCompletionBlock:^(NSError *error, Firebase *ref) {
if (!error) {
[newPhotoRef updateChildValues:photoInformation withCompletionBlock:^(NSError *error, Firebase *ref) {
if (!error) {
// Uploaded image to Amazon S3 and reference to Firebase
}
}];
}
}];
} else {
// Error uploading
}
return nil;
}];
}
Edit
The method should be a block method, something like this:
-(void)uploadImage:(UIImage *)image withBlock:(void (^)(Firebase *ref, NSError *error, AWSTask *task))handler
{
// upload
}

Google Objective c api : completionHandler never called when there is no internet connection

iOS beginner, I am trying to upload videos on youtube using the google objective c api.
In most cases, it just works. Videos can be uploaded and my callback receives errors if they occur.
But if I turn off the internet connection on the device, the callback is never called. (even though it is called for other types of errors, like incorrect title or incorrect tags)
My personal guess it that while I have set a callback for GTLServiceYouTube, I haven't explicitly set one for GTMOAuth2Authentication, hence the absence of a call. But I am not sure how to set one and found nothing about it anywhere.
Note that in my situation, I really need my users to be able to upload a video without having to enter their credentials, hence the manual initialization of the GTMOAuth2Authentication.
Here is my code, please tell me if I am doing something wrong and how I could fix it.
NSString *clientID = #"185815387242-hqo2d4e06j4hk4f02t5gvn7jcifakdvr.apps.googleusercontent.com";
NSString *clientSecret = #"2LKi7orHyphJXXXXXXXXXXXX";
NSURL *tokenURL = [NSURL URLWithString:#"https://accounts.google.com/o/oauth2/token"];
NSString *redirectURI = #"urn:ietf:wg:oauth:2.0:oob";
GTMOAuth2Authentication *auth;
auth = [GTMOAuth2Authentication authenticationWithServiceProvider:kGTMOAuth2ServiceProviderGoogle
tokenURL:tokenURL
redirectURI:redirectURI
clientID:clientID
clientSecret:clientSecret];
[auth setKeysForResponseString:#"email=annonce-video-i-6620%40pages.plusgoogle.com&isVerified=1&refresh_token=1%2FFFo5rlNs51u9g2TpCIE2oji_ACvDPc0XXXXXXXXXXXX&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&serviceProvider=Google&userID=107586507912247324352"];
//////////////////////////////////////////////////
GTLServiceYouTube *youTubeService = [[GTLServiceYouTube alloc] init];
// Have the service object set tickets to fetch consecutive pages
// of the feed so we do not need to manually fetch them.
youTubeService.shouldFetchNextPages = YES;
// Have the service object set tickets to retry temporary error conditions
// automatically.
youTubeService.retryEnabled = YES;
youTubeService.authorizer = auth;
// Status.
GTLYouTubeVideoStatus *status = [GTLYouTubeVideoStatus object];
// Snippet.
GTLYouTubeVideoSnippet *snippet = [GTLYouTubeVideoSnippet object];
snippet.title = #"TITLE";
NSString *desc = #"DESC";
if ([desc length] > 0) {
snippet.descriptionProperty = desc;
}
NSString *tagsStr = #"TAGS";
if ([tagsStr length] > 0) {
snippet.tags = [tagsStr componentsSeparatedByString:#","];
}
GTLYouTubeVideo *video = [GTLYouTubeVideo object];
video.status = status;
video.snippet = snippet;
// Get a file handle for the upload data.
NSString *path = #"AVALIDPATH";
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:path];
if (fileHandle) {
NSString *mimeType = #"video/mp4";
GTLUploadParameters *uploadParameters =
[GTLUploadParameters uploadParametersWithFileHandle:fileHandle
MIMEType:mimeType];
uploadParameters.uploadLocationURL = nil;
GTLQueryYouTube *query = [GTLQueryYouTube queryForVideosInsertWithObject:video
part:#"snippet,status"
uploadParameters:uploadParameters];
GTLServiceYouTube *service = youTubeService;
[service executeQuery:query
completionHandler:^(GTLServiceTicket *ticket,
GTLYouTubeVideo *uploadedVideo,
NSError *error) {
//NEVER CALLED WHEN THE DEVICE IS IN AIRPLANE MODE
NSLog(#"And call me maybe.");
}];
I have traced back the absence of call to GTMHTTPFetcher line 969
#synchronized(self) {
target = [[delegate_ retain] autorelease];
sel = finishedSel_;
#if NS_BLOCKS_AVAILABLE
block = [[completionBlock_ retain] autorelease];
#endif
}
The synchronized block is called twice, once to call the GTMOAuth2Authentication callback, and a second time to call... Well... nil
A bug in retry handling on uploads was recently fixed in the library. Try updating your Google API library sources.

NSFileCoordinator correct usage for sqlite journal file in sandbox Mac App Store app

I have a lot of troubles porting my sqlite code to the App Store due to the way sqlite executes transactions (using wal or journal files). Relevant part from Apple Documentation is:
Your app needs to be able to open or save multiple related files with the same name and different extensions (for example, to automatically open a subtitle file with the same name as a movie file, or to allow for a SQLite journal file). To gain access to that secondary file, create a class that conforms to the NSFilePresenter protocol. This object should provide the main file’s URL as its primaryPresentedItemURL property, and should provide the secondary file’s URL as its presentedItemURL property. After the user opens the main file, your file presenter object should call the addFilePresenter: class method on the NSFileCoordinator class to register itself.
Apple DTS provides me the following code:
- (void)openSQLiteFileAtURL:(NSURL *)fileURL {
NSFileCoordinator *fc = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
[fc coordinateReadingItemAtURL:fileURL options:0 error:NULL byAccessor:^(NSURL *newURL) {
sqlite3 *db = NULL;
char *zErrMsg = 0;
[SQLiteRelatedItemPresenter addPresentersForURL:newURL];
int rc = sqlite3_open_v2([[newURL path] fileSystemRepresentation], &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
NSLog(#"open %# = %d", [newURL path], rc);
rc = sqlite3_exec(db, "CREATE TABLE foo (col1 INTEGER);", callback, 0, &zErrMsg);
if( rc!=SQLITE_OK ){
NSLog(#"SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}
// more sqlite code here
sqlite3_close(db);
}];
return;
}
where SQLiteRelatedItemPresenter is:
#interface SQLiteRelatedItemPresenter : NSObject <NSFilePresenter>
{
NSURL *primaryPresentedItemURL;
NSURL *presentedItemURL;
}
static NSOperationQueue *_presentedItemOperationQueue;
#implementation SQLiteRelatedItemPresenter
+ (void) initialize {
[super initialize];
if (_presentedItemOperationQueue == nil) {
_presentedItemOperationQueue = [[NSOperationQueue alloc] init];
}
}
+ (void)addPresentersForURL:(NSURL *)databaseURL {
SQLiteRelatedItemPresenter *p1, *p2, *p3, *p4;
p1 =[[SQLiteRelatedItemPresenter alloc] initWithFileURL:databaseURL prefix:nil suffix:#"-wal"];
[NSFileCoordinator addFilePresenter:p1];
p2 = [[SQLiteRelatedItemPresenter alloc] initWithFileURL:databaseURL prefix:nil suffix:#"-shm"];
[NSFileCoordinator addFilePresenter:p2];
p3 = [[SQLiteRelatedItemPresenter alloc] initWithFileURL:databaseURL prefix:nil suffix:#"-journal"];
[NSFileCoordinator addFilePresenter:p3];
p4 = [[SQLiteRelatedItemPresenter alloc] initWithFileURL:databaseURL prefix:#"." suffix:#"-conch"];
[NSFileCoordinator addFilePresenter:p4];
// +filePresenters will only return once the asynchronously added file presenters are done being registered
[NSFileCoordinator filePresenters];
}
- initWithFileURL:(NSURL *)fileURL prefix:(NSString *)prefix suffix:(NSString *)suffix {
self = [super init];
if (self) {
primaryPresentedItemURL = fileURL;
NSString *path = [fileURL path];
if (prefix) {
NSString *name = [path lastPathComponent];
NSString *dir = [path stringByDeletingLastPathComponent];
path = [dir stringByAppendingPathComponent:[prefix stringByAppendingString:name]];
}
if (suffix) {
path = [path stringByAppendingString:suffix];
}
presentedItemURL = [NSURL fileURLWithPath:path];
}
return self;
}
- (NSURL *)presentedItemURL {
return presentedItemURL;
}
- (NSOperationQueue *)presentedItemOperationQueue {
return _presentedItemOperationQueue;
}
- (NSURL *)primaryPresentedItemURL {
return primaryPresentedItemURL;
}
This specific example works fine for sqlite operations all executed inside the openSQLiteFileAtURL method. I am having a lot of troubles if I try to divid logic into sub-methods, for example:
- openSQLiteFileAtURL:(NSURL *)databaseURL; // just open the db
- executeSQLStatement:(NSString *)sql; //perform read/write operations into the sqlite db previously opened in the openSQLiteFileAtURL method
- closeSQLite(); //close db method.
Seems like that addPresentersForURL should be called only once (in openSQLiteFileAtURL) but I wasn't able to have a working app due to sandbox privileges errors... any help?

Resources