iPhone - tracking back button - iphone

I have a tableView which lists the contents of my document directory. I have some zip files in that. If I touch a file in the tableView, the corresponding zip file is unzipped and extracted in a temporary directory(newFilePath in my case). The contents unzipped is listed in the next tableView. When I touch the back button, the contents in the directory is listed again.
For example, consider that I have four zip files in my document directory.
songs.zip, videos.zip, files.zip, calculation.zip
When I run the application, all the four files are listed in the tableView. When I touch songs.zip, this file is extracted in the newFilePath and its contents are pushed to the next tableView. When I touch back, the previous tableView, i.e, the four files in the document directory are listed again. Everything works perfect.
The problem is, the extracted files in the newFilePath remains there itself. They occupy the memory unnecessarily. I want them to be removed from that path when I touch the back button, i.e, I want to make newFilePath empty when the back button is touched.
I tried for it. But, no use. I tried removeItemAtPath: method in viewWillAppear: and also in viewWillDisappear:. But it didnt work in both the cases.
Is there any other method to track the action of the back button? I want an event to take place when the back button is touched. So please help me by sharing your ideas. Here is my code for your verification.
This is my didSelectRowAtIndexPath:
NSString *filePath = //filePath
if([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSLog(#"File exists at path: %#", filePath);
} else {
NSLog(#"File does not exists at path: %#", filePath);
}
ZipArchive *zip = [[ZipArchive alloc] init];
NSString *newFilePath = //newFilePath
[[NSFileManager defaultManager] createDirectoryAtPath:newFilePath withIntermediateDirectories:NO attributes:nil error:nil];
BOOL result = NO;
if([zip UnzipOpenFile:filePath]) {
//zip file is there
if ([zip UnzipFileTo:newFilePath overWrite:YES]) {
//unzipped successfully
NSLog(#"Archive unzip Success");
result= YES;
} else {
NSLog(#"Failure To Extract Archive, maybe password?");
}
} else {
NSLog(#"Failure To Open Archive");
}
iDataTravellerAppDelegate *AppDelegate = (iDataTravellerAppDelegate *)[[UIApplication sharedApplication] delegate];
//Prepare to tableview.
MyFilesList *myFilesList = [[MyFilesList alloc] initWithNibName:#"MyFilesList" bundle:[NSBundle mainBundle]];
//Increment the Current View
myFilesList.CurrentLevel += 1;
viewPushed = YES;
//Push the new table view on the stack
myFilesList.directoryContent = [AppDelegate getTemporaryDirectoryItemList:newFilePath];
[myFilesList setTitle:detailedViewController.strName];
[self.navigationController pushViewController:myFilesList animated:YES];
[myFilesList release];
Thank you for your answers.

Oh ya, thats quite simple:
in LoadView,
self.navigationItem.leftBarButtonItem=[[UIBarButtonItem alloc]
initWithTitle:#"Back"
style:UIBarButtonItemStylePlain
target:self
action:#selector(backButtonHit)];
-(void)backButtonHit
{
// removeItemAtPath: newFilepath stuff here
[self.navigationController popViewControllerAnimated:YES];
}

Related

Can't use core database in IOS5

I am working with a core database, it is working in IOS 6 but when I trying to test it on IOS 5. It does not do anything. Let me explain what I'm doing.
First I do this in my viewWillAppear.
- (void)viewWillAppear:(BOOL)animated
{
NSLog(#"view appeared");
[super viewWillAppear:animated];
if (!self.genkDatabase) {
NSLog(#"comes to here");
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
url = [url URLByAppendingPathComponent:#"Default appGenk Database2"];
// url is now "<Documents Directory>/Default Photo Database"
self.genkDatabase = [[UIManagedDocument alloc] initWithFileURL:url]; // setter will create this for us on disk
NSLog(#"database created on disk");
}
}
Then it comes in the UseDocument method.
- (void)useDocument
{
NSLog(#"Comses in the use document");
if (![[NSFileManager defaultManager] fileExistsAtPath:[self.genkDatabase.fileURL path]]) {
// does not exist on disk, so create it
[self.genkDatabase saveToURL:self.genkDatabase.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
NSLog(#"create");
[self setupFetchedResultsController];
[self fetchGenkDataIntoDocument:self.genkDatabase];
}];
} else if (self.genkDatabase.documentState == UIDocumentStateClosed) {
NSLog(#"closed news");
// exists on disk, but we need to open it
[self.genkDatabase openWithCompletionHandler:^(BOOL success) {
[self setupFetchedResultsController];
}];
} else if (self.genkDatabase.documentState == UIDocumentStateNormal) {
NSLog(#"normal");
// already open and ready to use
[self setupFetchedResultsController];
}
}
And finally it goes into the setDatabase Method.
- (void)setGenkDatabase:(UIManagedDocument *)genkDatabase
{
if (_genkDatabase != genkDatabase) {
_genkDatabase = genkDatabase;
[self useDocument];
}
NSLog(#"Comes in the setdatabase methode.");
}
Doing all this gives the following log.
2012-10-22 10:42:47.444 RacingGenk[4786:c07] view appeared
2012-10-22 10:42:47.445 RacingGenk[4786:c07] comes to here
2012-10-22 10:42:47.459 RacingGenk[4786:c07] Comses in the use document
2012-10-22 10:42:47.460 RacingGenk[4786:c07] Comes in the setdatabase methode.
2012-10-22 10:42:47.461 RacingGenk[4786:c07] database created on disk
Like you can see it does not print the create log in my use document. So it isn't able to execute the method FetchDataIntoDocument.
Can anybody help me with this problem. I am searching at this problem for ages for now.
Many thanks in advace.
Stef
Are you testing with the simulator or on the device?
The simulator is case-insensitive - the device is case-sensitive on file access, remember that!
But beside from that the documentation for NSFileManager recommends not checking to see if files exist, and instead just trying to read the file and handle any errors gracefully (e.g. file not found error). So just try loading the file instead of checking to see if it exists.
And i don't see any file extension for your database file! It just states ""Default appGenk Database2".
Is this already the file name or jut another subdirectory so far?
EDIT:
You can try the following code:
- (void) setupStore {
NSString* storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"mydatabase.sqlite"];
// Set up the store.
NSFileManager* fileManager = [NSFileManager defaultManager];
// If the expected store doesn't exist, create one.
if (![fileManager fileExistsAtPath: storePath]) {
// create your store here!
}
}
- (NSString*) applicationDocumentsDirectory {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}
"mydatabase.sqlite" is the name of the database-file you expect to be present in your documents directory.
If you would like to see a full-fledged example on how to set-up a core data persistent store you could check out apples own iPhoneCoreDataRecipes example. Just take a look at the
RecipesAppDelegate.m
implementation.

Would like to keep cache data when changing to other UIView

i would love to have some help or any keyword that i can use to search for.
My problem is I have one UIView, called "UpdateViewController.xib" that load 20 small images and text below those images by programmatically.
and when user click on those images it will change to next view that i created by IB, called "imageSumVuew.xib" and i have a button to link back to UpdateViewController.
#import "imageSumView.h" // next view that i wanna load//
// the transition to next view
imageSumView *nextView = [[imageSumView alloc]init];
self.modalPresentationStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:nextView animated:YES completion:NULL];
[nextView release];
in the nextView i have code similar to this which come back to this view
#import "UpdateViewController.h" // old that i wanna load back//
// the transition to old view
UpdateViewController *oldView = [[UpdateViewController alloc]init];
self.modalPresentationStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:oldView animated:YES completion:NULL];
[oldView release];
the problem is when it did load back to UpdateViewController, all my images and text has to reload all over again.
The question is " how can i keep cache of the UpdateViewController view?", i don't want user to reload images all over again because they have to go back and forth between this page for several times to see which image that they wanna pick.
Think of Instragram that you see list of your friends images then you wanna check your first friends's photo and after that you come back to overall image of your friends without loading and choose second friends.
Store image data with unique id to temporary directory once it is downloaded for the first time. For the next time check for that user id's image in your directory, if it is there then load image from there. For example :
#define TMP NSTemporaryDirectory()
NSString *filename=[NSMutableString stringWithFormat:#"userimage_%#",userId];
NSString *uniquePath = [TMP stringByAppendingPathComponent:filename];
NSData *dataImage = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageUrl]]
UIImage *image = [[UIImage alloc] initWithData: dataImage];
[UIImageJPEGRepresentation(image, 1.0f) writeToFile: uniquePath atomically: YES];
[image release];
To get ur image you can do something like below:
- (NSData *) getImage: (NSString *)userId
{
NSString *filename=[NSMutableString stringWithFormat:#"userimage_%#,userId];
NSString *uniquePath = [TMP stringByAppendingPathComponent: filename];
if([[NSFileManager defaultManager] fileExistsAtPath: uniquePath])
{
return [[NSData alloc] initWithContentsOfFile:uniquePath];
}
return nil;
}

Xcode: How would I do a one-off UIAlertView?

I have an app that I want to bring up an alert view to ask them if they can review the app?
Any help appreciated!
Don't. That is bad UX. Instead, try the following:
have an "About" section in your app containing your brand, and a link to the review page
have a "Review This App" button in a non-distracting location at a corner/side of the screen where it doesn't break the user experience
Something like this would do it:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"UIAlertView" message:#"<Alert message>" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK", nil];
[alert show];
[alert release];
* Important Update
Apple has added an extra rule for apps being submitted to the app store.
We can no longer store arbitrary data files in the Documents folder. Only content generated by the user like a text file they manually typed and saved or a photo they took with the camera can be saved in the Documents folder.
We are now expected to store our app generated files in the Library/Cache folder instead of the Documents folder. In addition, we should mark the files we don't want to be sync to iCloud with the skip backup attribute.
Failure to comply with this will result in an app being rejected by Apple.
Reason: The Documents folder is now used for syncing to iCloud. iCloud does a sync every few minutes and if we were to have megabytes of our app generated files stored in the Documents folder, it would get mixed up with the user's own iCloud synced files.
Update the MediaDirectory.m files with these new code to be safe:
+ (NSString *) mediaPathForFileName:(NSString *) fileName
{
NSArray *directoryPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachesDirectory = [directoryPaths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/%#", cachesDirectory, fileName];
return filePath;
}
+ (BOOL)addSkipBackupAttributeToFile:(NSString *) fileName
{
NSArray *directoryPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachesDirectory = [directoryPaths objectAtIndex:0];
NSString *filePathStr = [NSString stringWithFormat:#"%#/%#", cachesDirectory, fileName];
const char* filePath = [filePathStr fileSystemRepresentation];
const char* attrName = "com.apple.MobileBackup";
u_int8_t attrValue = 1;
int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
return result == 0;
}
Remember to mark that text file we generated with the skip backup attribute like so after generating the file:
[MediaDirectory addSkipBackupAttributeToFile:#"fileStatus.txt"];
I also had a typo earlier, I said to write to file "firstLaunch.txt" when it should have been "fileStatus.txt" (bad copy and paste skills :P)
Original Text
You could try writing a value (such as "no") to a text file and storing in the application's sandbox Document folder when the user taps on "Don't ask again" button.
Next time the app loads, your view controller would read the value from this text file and if it's "no", then don't display the alert view.
Hope that helps.
Writing a one off UI alert view
OK, let me first explain the process we're going to go through:
1) Your application delegate class didFinishLaunchingWithOption is the method that gets called when an app is launched.
2) This method only gets called once when the app launches so this is the spot where we create a text file and we write our status of the alert view whether to "show again" or "don't show again" for the UIAlertView
3) We're going to bring up the alert view in your UIViewController's viewDidLoad method. However, we only display this UIAlertView IF the value in our text file IS NOT "don't show again". If the value in the text file is "show again", we show the UIAlertView, if it's "don't show again", we don't show the UIAlertView, makes sense?
(These values are only string, you can set any value you want, I'm only using these random values to demonstrate).
Right, now we got the general process, let's implement it.
The code
In your AppDelegate.h header file:
#interface MyAppDelegate : NSObject
{
...
bool isFirstLaunch;
}
Now in your AppDelegate.m implementation file:
// -------------------------------------------------------------------------------------
// I wrote a helper class called "MediaDirectory" that returns me the path to a file
// in the Documents directory of the application sandbox.
// Each application has a copy of the Documents directory so you can safely
// assume this directory will always exist.
//
// This class has been very useful for me, hope you find it useful too.
//
// DOWNLOAD THE FILES AT:
//
// http://www.chewedon.com/classes/MediaDirectory.h
// http://www.chewedon.com/classes/MediaDirectory.m
// -------------------------------------------------------------------------------------
#import <Foundation/NSFileManager.h>
#import <Foundation/NSFileHandle.h>
#import "MediaDirectory.h"
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
NSString *fileStatus = nil;
// Here, the NSFileManager defaultManager fileExistsAtPath method needs a path to
// the file in the Document directory, to get this path, use the static method from
// my MediaDirectory class and pass it the name of the file.
// I called it "fileStatus.txt"
//
// We're checking if the file exist in the Documents directory or not.
// If it does not exist then we create the text file and pass it the
// value "show again", otherwise we do nothing.
// (We don't want to overwrite the value everytime the app starts)
if([[NSFileManager defaultManager] fileExistsAtPath:[MediaDirectory mediaPathForFileName:#"fileStatus.txt"]] == NO)
{
// prepare fileStatus.txt by setting "show again" into our string
// we will write this string into the text file later
fileStatus = [[NSString alloc] initWithString:#"show again"];
// now we write the value "show again" so that the UIAlertView will show
// when it checks for the value, until the user clicks on no and we set
// this value to "don't show again" later in another piece of code
[fileStatus writeToFile:[MediaDirectory mediaPathForFileName:#"fileStatus.txt"]
atomically:YES
encoding:NSUTF8StringEncoding
error:nil];
}
[fileStatus release];
...
// rest of your didFinishLaunchingWithOptions method
[window addSubview:[viewController view]];
[self.window makeKeyAndVisible];
[self initGlobals];
return YES;
}
Now in your UIViewController class, we need to make this class conform to the UIAlertView protocol. We are going to use one of the delegate method that tells us when a button on the UIAlertView is clicked.
#interface MyViewController : UIViewController <UIAlertViewDelegate>
{
...
}
In our implementation file (MyViewController.m file) we check the value stored in the text file before showing the UIAlertView.
#import "MediaDirectory.h"
#import <Foundation/NSFileManager.h>
#import <Foundation/NSFileHandle.h>
-(void)viewDidLoad
{
...
BOOL shouldShowAlert = false;
NSString *fileStatus = nil;
// check if the file exists in the Documents directory and read its value
// if it does. If the value read from file is "show again",
// we bring up a UIAlertView
if([[NSFileManager defaultManager] fileExistsAtPath:[MediaDirectory mediaPathForFileName:#"fileStatus.txt"]] == YES)
{
fileStatus = [[NSMutableString alloc] initWithContentsOfFile:[MediaDirectory mediaPathForFileName:#"fileStatus.txt"]
encoding:NSUTF8StringEncoding
error:nil];
if([fileStatus isEqualToString:#"show again"] == YES)
{
shouldShowAlert = true;
}
else if([fileStatus isEqualToString:#"don't show again"] == YES)
{
shouldShowAlert = false;
}
}
if(shouldShowAlert == true)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"My Alert View Title"
message:#"my message"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:#"Don't Show Again", nil];
// we set a tag for this UIAlertView to distinguish between this UIAlertView
// and other UIAlertView in case there are any.
// I use a value of 10, you can use any value but make sure it is unique
[alert setTag:10];
[alert show];
[alert release];
}
}
Now we come to the last part where we handle which button the user tapped on for the UIAlertView.
Somewhere in your MyViewController.m file, write this delegate method:
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
// making sure its the UIAlertView we want
if([alertView tag] == 10)
{
// By default, the "cancel" button has an index of 0
// and the next button would have a index of 1
// In our case, we set the first button is "OK"
// and "Don't Show Again" as second button
if(buttonIndex == 1)
{
NSString *fileStatus = [[NSString alloc] initWithString:#"don't show again"];
[fileStatus writeToFile:[MediaDirectory mediaPathForFileName:#"fileStatus.txt"]
atomically:YES
encoding:NSUTF8StringEncoding
error:nil];
[fileStatus release];
}
}
}
Hopefully I didn't miss anything, let me know if it works or not.

iPhone DrillDown

Hai all. I have a tableView which lists the contents of my document directory. I have some zip files in that. If I touch a file in the tableView, the corresponding zip file is unzipped and extracted in a temporary directory(NSTemporaryDirectory()).
The problem is how to navigate the contents which I extracted in a tableView. If suppose, the extracted zip file contains folders, I should able to view them in a tableView. Actually the flow should be like a DrillDown.
I can able to extract the zip files, but problem is, have to navigate them in a tableView. Please give me some ideas or some source codes which helps my problem.
This is my didSelectRowAtIndexPath: part,
NSString *filePath = //filePath;
if([[NSFileManager defaultManager]fileExistsAtPath:filePath]) {
NSLog(#"File exists at path: %#",filePath);
} else {
NSLog(#"File does not exists at path: %#", filePath);
}
NSString *tmpDir =NSTemporaryDirectory();
ZipArchive *zip = [[ZipArchive alloc] init];
BOOL result = NO;
if([zip UnzipOpenFile:filePath]) {
//zip file is there
if ([zip UnzipFileTo:tmpDir overWrite:YES]) {
//unzipped successfully
NSLog(#"Archive unzip Success");
result= YES;
} else {
NSLog(#"Failure To Extract Archive, maybe password?");
}
} else {
NSLog(#"Failure To Open Archive");
}
if([[NSFileManager defaultManager]fileExistsAtPath:tmpDir isDirectory:&isDir] && isDir) {
NSLog(#"Its Folder");
//Prepare to tableview.
RootViewController *rvController =[[RootViewController alloc]initWithNibName:#"RootViewController"bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:rvController animated:YES];
}
But its not working. Its pushing the same contents in the document directory in the tableView
Please help me..
Thank you..
where do you tell your RootViewController to open a new path? For me it looks like you open the same RootViewController again with the old path so it's sure to open the same path again
You should add a property for setting the current file path to your controller class.
You can write a designated initializer like:
- (id)initWithDirectoryPath:(NSString*)path {
self = [super initWithNibName:#"DirectoryViewController" bundle:nil];
if (self != nil) {
self.directoryPath = path;
self.navigationItem.title = [path lastPathComponent];
}
}
Then you can create your view controller and push it on the navigation controller with:
DirectoryViewController *viewController = [[DirectoryViewController alloc] initWithDirectoryPath:path];
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
Don't forget to release the VC!

How to call a method on background thread

in my app i am unzipping a zip file(in splash view controller) later i am displaying an image and firing a timer with 4 secs to change image of the previous image view. and later in view did appear i am firing another timer with 10 secs to call next view controller(home view controller).. and there i have a button to go Story view controller...in this i am using the unzipped data...its taking some time to unzip in this case. so the images r displaying later a few seconds...it fine here
the problem is... i called the unzipping on background thread so its displaying the images quickly and its moving to home view controller..while going to next view controller by clicking a button its crashing on device but its working fine in simulator..
can any body help me out please
Thanks.
code...
-(void)viewWillAppear:(BOOL)animated{
[self performSelectorInBackground:#selector(unXip) withObject:nil];
CGRect imageFrame = CGRectMake(0,20,320,460);
splashView.frame = imageFrame;
splashView.image = [UIImage imageNamed:#"Default.png"];
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(changeImg) userInfo:nil repeats:NO];
[NSTimer scheduledTimerWithTimeInterval:3 target:self selector:#selector(changeImg2) userInfo:nil repeats:NO];
}
-(void)unXip{
self.fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
self.documentsDir = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/temp", self.documentsDir];
NSString *filePathbmlg = [NSString stringWithFormat:#"%#/temp/bmlg", self.documentsDir];
NSString *updateURL = [[NSBundle mainBundle] pathForResource:#"bmlg" ofType:#"zip" inDirectory:#"res"];
[fileManager createDirectoryAtPath:filePath
withIntermediateDirectories:NO
attributes:nil
error:nil];
if([fileManager fileExistsAtPath:filePath]) {
NSLog(#"File exists at path: %#", updateURL);
} else {
NSLog(#"File does not exists at path: %#", updateURL);
}
NSLog(#"Checking update at : %#", updateURL);
NSLog(#"Checking filepath at : %#", filePath);
if(![fileManager fileExistsAtPath:filePathbmlg]) {
ZipArchive *zipArchive = [[ZipArchive alloc] init];
if([zipArchive UnzipOpenFile:updateURL]) {
if ([zipArchive UnzipFileTo:filePath overWrite:YES]) {
//unzipped successfully
NSLog(#"Archive unzip Success");
//[self.fileManager removeItemAtPath:filePath error:NULL];
} else {
NSLog(#"Failure To Unzip Archive");
}
} else {
NSLog(#"Failure To Open Archive");
}
[zipArchive release];
}
}
- (void)changeImg{
splashView.image = [UIImage imageNamed:#"screen2.png"];
}
- (void)changeImg2{
splashView.image = [UIImage imageNamed:#"screen3.png"];
}
- (void)viewDidAppear:(BOOL)animated{
[NSTimer scheduledTimerWithTimeInterval:15 target:self selector:#selector(pushCVC) userInfo:nil repeats:NO];
}
- (void)pushCVC{
homeViewController = [[HomeViewController alloc] initWithNibName:#"HomeView" bundle:nil];
[self presentModalViewController:homeViewController animated:YES];
}
It's kind of hard to answer this witout any sample code. One thing to be aware of when using background threads is to make sure that all code that updates the UI runs on the main thread.
Ok, I think this is probably a threading issue. Your unXip method is modifying something on a background thread and then you try to access that "something" from another thread (main thread if you access it from UI code). You need to implement some kind of locking/synchronization mechanism (e.g. NSLock or NSConditionLock).
It looks a bit strange that you are using a timer to call pushCVC. Now, I don't know exactly what your app does but wouldn't it be better to call pushCVC when the unzip has finished by adding this to the end of your unXip method:
[self performSelectorOnMainThread:#selector(pushCVC) withObject:nil waitUntilDone:NO];
and removing the timer.
thanks for your comments and answers....
The problem is the unzipping process is taking a long time...so if i click start button on the home screen before the completion of the unzipping the file, its crashing...because i have to use the data from unzipped file...
Thanks again..