I am having trouble with updating my tableView.
In the tableView of the popover managed by the rootviewcontroller, some items in my documents directory are displayed. In the detailViewcontroller, i change the names of those files by using the NSFilemanager. Regardless what I do, the tableView won't display the new ones. I get to see them if i close the app and open it again. At the moment, i try using notifications, but it doesn't work …
EDIT
I logged my documents directory, its definitely not a tableView problem, moreover, it works out well, but the second time I enter some text, nothing happens…
DetailViewController
- (void)textFieldDidEndEditing:(UITextField *)tf
{
textLabel.text = textField.text;
NSString* newName = textLabel.text;
newName = [newName stringByAppendingPathExtension:#"txt"];
NSString* newPath = [[currentFilePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:newName];
NSLog(#"%#",newPath);
[[NSFileManager defaultManager] moveItemAtPath:currentFilePath toPath:newPath error:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"DataSaved" object:nil];
}
RootViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView initWithFrame:self.tableView.frame style:UITableViewStyleGrouped];
self.clearsSelectionOnViewWillAppear = NO;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(dataSaved:) name:#"DataSaved" object:nil];
}
- (void)dataSaved:(NSNotification *)notification
{
[self loadDirectoryContents];
[self.tableView reloadData];
}
[self.tableView initWithFrame:self.tableView.frame style:UITableViewStyleGrouped];
This line looks a bit suspicious. How are you constructing your tableview?
It works out when I type in something. But if i type in something the second time without having anything selected in the tableView, the fileManager doesn't move the item to the path. Any suggestions? It doesnt seem to be a tableView related Problem.
I also thought I needed to set:
currentFilePath = newPath;
But that gave me a EXC_BAD_ACCESS.
Related
I have two views in my app and a plist file to store some values.
In the first view I've created a button called frequenciesButton that opens the second view and another button to restore the default values.
In the second view there is a pickerView and a "Done" button.
On the .m of the first view:
- (void)viewDidLoad {
[super viewDidLoad];
//
self.gameSettings = [[NSMutableDictionary alloc] initWithContentsOfFile:gameSettingsFilePath];
}
-(void)viewWillAppear:(BOOL)animated {
[self refreshView];
}
- (void)refreshView {
[self.frequenciesButton setTitle:[NSString stringWithFormat:#"%# hz and %# hz", [self.gameSettings objectForKey:#"freq-freq1"], [self.gameSettings objectForKey:#"freq-freq2"]] forState:UIControlStateNormal];
...
}
- (IBAction)setDefaultValues:(UIButton *)sender {
[self.gameSettings setValue:#880 forKey:#"freq-freq1"];
[self.gameSettings setValue:#1122 forKey:#"freq-freq2"];
...
[self.gameSettings writeToFile:gameSettingsFilePath atomically:YES];
[self refreshView];
}
When the first view is loaded, the button title is changed to the default values stored in the gameSettings dictionary. The method setTitle: works.
When I click on the frequenciesButton it opens the second view with the pickerView, I select the two new values for the freq-freq1 and freq-freq2 and it saves to the plist file on done button.
The problem is that the frequenciesButton title is not changed when the second view is dissmissed and the first view appears. The refreshView method is called but the button setTitle: does not work.
In this case, if I go back one screen, and return to this view, the button title is updated.
And when I click on defaultValuesButton, the frequenciesButton title changes. The method setTitle: also works.
Any ideas of what must be happening?
HaHA! I love that you added a link to your project.
SO!! The problem was that you have separate properties in each view to hold the data from the saved plist file, self.settings. This is fine, don't mesh them together. The requirement you had to do with this, when switching views, is to keep the ivar or properties updated as the data updates too :D
Here is how I fixed the problem:
- (void)viewWillAppear:(BOOL)animated {
self.settings = [NSMutableDictionary dictionaryWithContentsOfFile: filePath];
[self updateView];
}
I checked out the file and that was updated, but the dictionary in the TestViewController.h was not updated
I hope this was the problem :)
One problem there, not sure if it will fix it, is the fact that you have used ViewWillAppear incorrectly, you have this:
-(void)viewWillAppear:(BOOL)animated {
[self refreshView];
}
but it should be this:
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self refreshView];
}
You need to invoke "[super viewWillAppear:animated];" or you will have side effects, fix that first and see what happens.
I'm using SWRevealViewController to get the side menu to show different content based on which tab the user is currently on. I've created a global variable in called location in AppDelegate to find out where the user is. For my sidebar, I'm using this condition to change the content:
- (void)viewWillAppear:(BOOL)animated {
[super viewDidAppear:animated];
AppDelegate *del=(AppDelegate*)[[UIApplication sharedApplication] delegate];
if ([del.location isEqualToString: #"Secure"]){
self.menu = [NSMutableArray
arrayWithObjects:#"secure1",#"secure2",#"secure3",#"secure4",#"secure5", nil];
self.menu2 = [NSMutableArray
arrayWithObjects:#"s1",#"s2",#"s3",nil];
NSLog(#"THIS IS %# menu",del.location);
}
else if ([del.location isEqualToString: #"Employee"]){
self.menu = [NSMutableArray
arrayWithObjects:#"emp1",#"emp2",#"emp3",#"emp4",#"emp5",#"emp6", nil];
self.menu2 = [NSMutableArray
arrayWithObjects:#"e1",#"e2",#"e3",nil];
NSLog(#"THIS IS %# menu",del.location);
}
else if ([del.location isEqualToString: #"Patient"]){
self.menu = [NSMutableArray
arrayWithObjects:#"patient1",#"patient2",#"patient3",#"patient4",#"patient5",#"patient6", nil];
self.menu2 = [NSMutableArray
arrayWithObjects:#"p1",nil];
NSLog(#"THIS IS %# menu",del.location);
}
}
It seems to be working as the NSLog statements all come out correctly, but the content for menu and menu2 still do not change. Where am I going wrong?
I wasn't adding the
[self.tableView reload];
after closing the if-statement, and instead added it under cellForRowAtIndexPath (which lead the cells to constantly reload, but not the table -- if my understanding is correct.)
Added it in the viewWillAppear after closing my if-statement and problem solved.
Thanks to Anbu.Karthik for pointing it out!
I have a routine in my iOS program that imports and manipulates a file from Dropbox. This can take some time (5-10 seconds) and it doesn't make sense to return the user to the normal UI while it's doing it, so I want to present a view letting the user know what the progress is.
From one VC, I use Dropbox's drop-in file picker, then load up a presented (modal VC) thus:
ZSImportVC *importVC = [[ZSImportVC alloc] init];
importVC.results = results;
[importVC setModalPresentationStyle:UIModalPresentationFormSheet];
[self presentViewController:importVC animated:YES completion:^{
[self performFetch];
}];
The VC (a bog-standard UIViewController), has a UILabel property:
#property (weak, nonatomic) IBOutlet UILabel *statusMessage;
In viewWillAppear: I can set the text of this label without any problem. The thing is, I want to keep changing this text as the process of manipulating the file continues.
The method that manipulates the file is called from viewDidAppear:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self processImport];
}
However, within the processImport method, the following has no effect:
self.statusMessage.text = #"Some text to update the user.";
So I created a method:
- (IBAction)updateStatus:(NSString *)message
{
[self.statusMessage setText:message];
NSLog(#"%#", message);
}
just to check what's going on. The NSLog shows that the method is being called okay, but the label text doesn't change. I tried adding:
[self.statusMessage setNeedsDisplay];
to the method, but that didn't help. I'm not using any private queues or background threads. I read somewhere that using NSNotification helps, so I tried adding this to viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(updateStatus:) name:#"updateStatus" object:nil];
Then changed the called method to:
- (void)updateStatus:(NSNotification *)message
{
[self.statusMessage setText:message.object];
NSLog(#"%#", message.object);
}
and called this from the main method with:
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateStatus" object:#"Retrieving file from Dropbox" userInfo:nil];
I could see from the console messages that the updateStatus method is getting called, but still the text doesn't change. Clearly I'm missing something here. Any thoughts?
Check your ZSImportVC instances on Debug perspective.
I think u are sending [self.statusMessage setText:message.object];
to another instance, that it is not shown on the screen.
I mean,
put a debug point here:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self processImport]; /* Debug point here*/
}
and check what´s the hexadecimal direction for self.
Now , do the same here:
- (void)updateStatus:(NSNotification *)message
{
[self.statusMessage setText:message.object]; /* Debug point here*/
NSLog(#"%#", message.object);
}
Btw, I had some problems with
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateStatus" object:#"Retrieving file from Dropbox" userInfo:nil];
because the instance that receive this notification was not the correct.
I fixed that calling a normal method, but u maybe could not do that.
Sorry for my english :S
My app is crashing while releasing view controller object.
Here is my code.
TagCloudWebViewController *controller=[[[TagCloudWebViewController alloc]init]autorelease];
controller.htmlString=[[notification userInfo] valueForKey:#"url"];
[self.navigationController pushViewController:controller animated:YES];
This is my code from wheny above method is called
-(void)viewDidLoad{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(openTextInWebview:) name:#"kTouchTextUrl" object:Nil];
}
and
#pragma mark - UIGestureDelegate
- (void)longPressRecognized:(UILongPressGestureRecognizer *)longPressRecognizer {
CGPoint touchPoint = [longPressRecognizer locationInView:self];
NSArray *subviews = self.subviews;
for (int i=0; i<subviews.count; i++) {
TagView * tagLabel = (TagView *)[subviews objectAtIndex:i];
if ( CGRectContainsPoint( [tagLabel frame], touchPoint ) ) {
NSArray*objectArray=[[[NSArray alloc] initWithObjects:tagLabel.customLink, nil] autorelease];
NSArray*keyArray=[[[NSArray alloc] initWithObjects:#"url", nil] autorelease];
NSDictionary *userInfo = [NSDictionary dictionaryWithObjects:objectArray forKeys:keyArray ];
[[NSNotificationCenter defaultCenter] postNotificationName:#"kTouchTextUrl" object:nil userInfo:userInfo];
//[[UIApplication sharedApplication] openURL:[NSURL URLWithString: tagLabel.customLink]];
break;
}
}
}
and this is notification method
DidLoad method
- (void) viewDidLoad {
[super viewDidLoad];
_webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
_webView.delegate = self;
_webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth
| UIViewAutoresizingFlexibleHeight);
_webView.scalesPageToFit = YES;
[self.view addSubview:_webView];
[self initSpinner];
if (htmlString) {
[self openURL:[NSURL URLWithString:htmlString]];
}
}
WebView delgate method
-(void) webViewDidStartLoad:(UIWebView *)webView {
self.navigationItem.title = #"Loading...";
[spinnerView startAnimating];
isLoading = YES;
}
-(void) webViewDidFinishLoad:(UIWebView*)webView {
self.navigationItem.title = [_webView stringByEvaluatingJavaScriptFromString:#"document.title"];
[self performSelector:#selector(stopSpinner) withObject:nil afterDelay:0.1];
isLoading = NO;
}
-(void) webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error {
[self webViewDidFinishLoad:webView];
[self performSelector:#selector(stopSpinner) withObject:nil afterDelay:0.1];
isLoading = NO;
}
(void) openURL:(NSURL*)URL {
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:URL];
[_webView loadRequest:request];
}
Update: The following answer was in response to the original question of why the UIViewController with a UIWebView was not appearing. The OP's original theory was that it was related to some problem regarding the premature releasing of the view controller object. But, as outlined in my answer below, I suspect the problem was related to the creation of the view controller itself. Anyway, my answer to the original question follows (but it unfortunately has nothing to do with the revised question):
I personally don't suspect the problem has anything to do with the
releasing of the controller. I think it is in the creation of the
controller's view. There's nothing in the above code that causes the
object to be released, so you problem rests elsewhere and you need to
show more code. If you're concerned about your notification center
stuff, try bypassing it and just add a button that does your
TagCloudWebViewController alloc/init, sets htmlString and pushes,
and see if that still causes your program to crash, which I suspect it
will.
I notice that you're creating your controller via alloc and init,
but not initWithNibNamed. According to the UIViewController Class
Reference:
"If you cannot define your views in a storyboard or a nib file,
override the loadView method to manually instantiate a view
hierarchy and assign it to the view property."
So, bottom line, either use a NIB, use a storyboard or define a
loadView. Defining a viewDidLoad doesn't preclude the need for a
loadView. You need to create a view for your controller, which is
done for you if you use NIB or storyboard, or you have to do manually
via loadView, if you don't use NIB or storyboard.
See
iPhone SDK: what is the difference between loadView and viewDidLoad?
for a discussion of the differences between viewDidLoad and
loadView.
I don not see any thing that causing crashing.I think you have changed your question.As per question you not using ViewController any where.Please show more details.
Updated: Please check, you are creating autoreleased object, it might be you are releasing some where by mistake.Try to avoid autoreleased object as it remain in the Pool and later releases ,which may causes a memory issue for you.
The above problem is occurs due to WebView delgate. After pressing back button the reference of the object is deallocating from memory due to this app is crashing while releasing the viewcontroller object. I did some thing like
-(void) viewDidDisappear:(BOOL)animated{
if([_webView isLoading]) {
[_webView stopLoading];
}
[_webView setDelegate:nil];
}
due to above code my crashing has been resolved
I have a view controller with many views and a tableview.
The tableview's cells are customized, so there is another class for setting up the cells.
In each cell there is a button. The image of this button changes depending on the cell's content (this content gets read from a DB).
Basically, when the user presses the button, it changes itself to another image, a new status is written to the DB but the tableview does not update itself automatically.
The method for the button is in the custom cell class, so I've tried to instantiate my view controller (the one with the tableview) and execute a method for updating some labels in the views and the tableview:
ViewControllerWithTable *vc = [[ViewControllerWithTable alloc] init];
[vc updateEverything];
But this doesn't work.
The same "updateEverything" method, called from the same "ViewControllerWithTable" (adding a reload button) works perfectly.
Adding the "[tableView reloadData]" in the viewWillAppear method won't work because all the action is done in the same view.
What am I missing?
EDIT: adding some code to be more clear.
This is the method I use to update the tableview. It's inside the ViewController with the embedded tableview and it works when triggered by a button in one of the views:
- (void) updateEverything {
// lots of DB writing and reading, plus label text changing inside all the views
[tableView reloadData];
}
This is the IBAction for the button press and it's in the custom cell class:
-(void) btnPresaPressed:(UIButton *)sender {
AppDelegate *deleg = (AppDelegate *)[[UIApplication sharedApplication] delegate];
deleg.did = sender.tag;
NSString *s1 = NSLocalizedString(#"ALERT_TITLE", nil);
NSString *s2 = NSLocalizedString(#"ALERT_BODY", nil);
NSString *s3 = NSLocalizedString(#"YES", nil);
NSString *s4 = NSLocalizedString(#"NO", nil);
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:s1
message:s2
delegate:self
cancelButtonTitle:s4
otherButtonTitles:s3, nil];
[alertView setTag:1];
[alertView show];
}
This method shows an alert view that calls another method, always in the custom cell class:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
AppDelegate *deleg = (AppDelegate *)[[UIApplication sharedApplication] delegate];
DbOperations *db = [[DbOperations alloc] init];
NSString *alrtTitle = [alertView buttonTitleAtIndex:buttonIndex];
NSString *s3 = NSLocalizedString(#"YES", nil);
NSString *s4 = NSLocalizedString(#"NO", nil);
switch (alertView.tag) {
case 1:
//
break;
case 2:
if ([alrtTitle isEqualToString:s3]) {
// DB writing and reading
ViewControllerWithTable *vc = [[ViewControllerWithTable alloc] init];
[vc updateEverything];
} else if ([alrtTitle isEqualToString:s4]){
//
}
break;
case 3:
if ([alrtTitle isEqualToString:s3]) {
//
}
break;
default:
break;
}
}
In this case, the updateEverything method don't work.
EDIT after you added more code:
In the following lines:
if ([alrtTitle isEqualToString:s3]) {
// DB writing and reading
ViewControllerWithTable *vc = [[ViewControllerWithTable alloc] init];
[vc updateEverything];
you are instantiating a new view controller altogether that has nothing to do with your original view controller that displayed the table view. So, you are sending the update message to the wrong object.
What you need is a mechanism for your cell to know which is the right controller to send the message to.
One easy solution would be using NSNotificationCenter:
the view controller register itself for a certain kind of notification:
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(updateEverything:)
name:kCellSentUpdateMessageNotification
object:nil];
your cell sends the notification, instead of calling the message directly:
[[NSNotificationCenter defaultCenter] postNotificationName:kCellSentUpdateMessageNotification object:nil];
OLD Answer:
You should call
[self.tableView reloadData]
from your updateEverything method implementation. This will reload the table data, effectively updating its rows appearance. The updateEverything method shall be called when tapping on the button in a row for this to work, obviously.
If that does not work, please provide more code.
Have you try to put
[[self tableView] reloadData];
I remember I had an issue like that, and this line on top solve my problem.
This is your problem:
The method for the button is in the custom cell class, so I've tried
to instantiate my view controller (the one with the tableview) and
execute a method for updating some labels in the views and the
tableview:
You created an entirely new view controller that has no knowledge of your tableview. The best thing to do is to create a property in your cell subclass and set it to your view controller when you set the cell. Then you can call your updateEverything method on that property.