I am trying to reload table of MyView.m from MySliderController.m but its not reloading.
i have declared below method in MyView.m
-(void)updateData{
[self.itablview reloadData];
}
and calling that method form MySliderController.m class by below code
DDMenuController *menuController = (DDMenuController*)((AppDelegate*)[[UIApplication sharedApplication] delegate]).DDmenuController;
MyView *obj = [[MyView alloc]init];
if(indexPath.row == 3){
[menuController showRootController:YES];
[obj updateData];
}
that method gets called but table is not reloading even i am checking existence of tableview by below code
-(void)reloadtable:(id) sender{
NSlog(#"%#",self.itableview)
[self.itableView reloadData];
}
in console i get (null)
but when i am checking in below code
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"%#", self.itableView);
}
i am getting below message . it means table exists
2013-06-29 19:31:48.673 slidingViews[7025:c07] <UITableView: 0x79d9400; frame = (0 0; 320 480); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x714e940>; layer = <CALayer: 0x714e3f0>; contentOffset: {0, 0}>
what can be the issue. Please check my code here
https://github.com/kanwarpalSingh/mycode
Your problem is that when you're instantiating the MyView you're actually creating a new (but not visible) version of the MyView view controller, not the original MyView you originated from. There are a few different methods to handle this and it really comes down to what works best for you.
One example would be to subscribe MyView to a custom notification originating from MySliderControl such as this...
MyView.m
- (void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(updateData:) name:#"updateDataOnMyView" object:nil];
}
MySliderControl.m
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateDataOnMyView" object:nil];
You can also use a delegate method if you don't like this setup. There are plenty of tutorials out there on creating your own delegates as well. Good luck!
Related
I have a view controller, when it's dissming with completion, I post a notfication, and in a subview which contained in another view controller, has added as a oberserve. But, when it tries to execute post notificaiton methode, exec_bad_access happend. what's wrong? The codes are:
BrandListByIdViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSNumber *bid = self.brands[indexPath.row][#"id"];
[self dismissViewControllerAnimated:YES completion:^{
[[NSNotificationCenter defaultCenter] postNotificationName:#"SelectedBrandId" object:nil];
}];
}
SearchNewProduct.h
#interface SearchNewProduct : UIView
#end
SearchNewProduct.m
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didSelectedBrandId::) name:#"SelectedBrandId" object:nil];
}
}
- (void)didSelectedBrandId:(NSNotification *)notif{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
Even I get rid of the userInfo, still bad access. I created a similar situation in another new project, it works fine.
I didn't realize that you were dealing with a UIView and not a UIViewController (should have read your question better). I think what is happening is that the View is receiving notifications even after being released. Make sure to call dealloc in your UIView and remove itself as an observer:
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Also, put an NSLog in that UIView's initWithFrame method to see if it is being called more than once.
This question is very similar:
ios notifications to "dead" objects
Not sure if this is the reason, but when you add your view to the notification center, your selector is wrong:
selector:#selector(didSelectedBrandId::)
There should only be one colon. The entire line should be:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didSelectedBrandId:) name:#"SelectedBrandId" object:nil];
Two colons indicates the method takes two arguments, but it only takes one.
I have a modalViewController that comes up over the top of a viewController with a tableView. When the user clicks a button on the modalViewController I want to reload the tableView within the viewController with this:
[tableView1 reloadData];
I do not want to put the reload in the viewDidAppear or viewWillAppear methods as they get called when i do not need the tableView to reload (i.e. when the user clicks the back button to return to the tableView).
Is there a way to do this?
Try
1) write one method which reloads the table data.
2) Call it on the back button clicked.
This is the classic delegate pattern problem, in your modal view controller you need a delegate reference to the current view controller presenting it
//Modal
#protocol ModalVCDelegate
- (void)tappedBackButton;
#end
#class ModalVC: UIViewController
#property id<ModalVCDelegate> delegate;
#end
#implementation
- (void)backButtonTapped:(id)sender
{
if (self.delegate)
[self.delegate tappedBackButton];
}
#end
Now, in your presenting VC, just process this delegate message
//Parent VC
- (void)showModal
{
ModalVC *vc = [ModalVC new];
vc.delegate = self;
//push
}
- (void)tappedBackButton
{
[self.tableView reloadData];
//close modal
}
You can use delegate . If find it more harder then alternative is to use NSNotificationCenter. You can see accepted answer for Refreshing TableView. This is really very short, easy and understandable way.
using Notification like bellow Method:-
Create NSNotificationCenter at yourViewController's ViewdidLoad Mehod
- (void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(ReloadDataFunction:)
name:#"refresh"
object:nil];
[super viewDidLoad];
}
-(void)ReloadDataFunction:(NSNotification *)notification {
[yourTableView reloadData];
}
Now you can Call this Notification from your modelViewController BackButton or else you want from calling this Refresh notification like putting this line of code:-
[[NSNotificationCenter defaultCenter] postNotificationName:#"refresh" object:self];
NOTE: postNotificationName:#"refresh" this is a key of particular Notification
Try to use this one
Make a Button and click on this button and than you can reload your data.
This button make custom and use it on background.
- (IBAction)reloadData:(id)sender
{
[tblView reloadData];
}
You can use NSNotification to refresh table on ViewController.
Inside viewController :
-(void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
Write code in viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reloadMainTable:)
name:#"ReloadTable"
object:nil];
- (void) reloadMainTable:(NSNotification *) notification
{
[tableView reload];
}
Inside ModelViewController:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"ReloadTable"
object:nil];
Here you can also send custom object instead of nil parameter. But be care full about removal of NSNotification observer.
I know there have been a couple questions asked similar to this, but I think my issues is a little different, so bear with me.
I have a tabbed view app with table views set in 2 of the 3 tabs. I want to be able to refresh just the table view of the selected tab when the app wakes back up. I have tried using the notification center to tell my tab to refresh, but it makes the other tab crash because it is stealing the view from my progress hud. I will put some code here, so hopefully I can find a solution that will work for me.
Tab 1 ViewController
- (void)viewDidLoad {
// becomeActive just calls viewDidAppear:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(becomeActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
[super viewDidLoad];
}
-(void)viewDidAppear:(BOOL)animated {
HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:HUD];
HUD.delegate = self;
HUD.labelText = #"Updating";
HUD.detailsLabelText = #"Please Wait";
[HUD showWhileExecuting:#selector(refreshData) onTarget:self withObject:nil animated:YES];
}
Tab 2 ViewController
- (void)viewDidLoad
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
self.navigationItem.title = [defaults valueForKey:#"companyName"];
self.view.backgroundColor = background;
tableView.backgroundColor = [UIColor clearColor];
tableView.opaque = YES;
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
// becomeActive just calls viewDidAppear
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(becomeActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
if (_refreshHeaderView == nil) {
EGORefreshTableHeaderView *view = [[EGORefreshTableHeaderView alloc] initWithFrame:CGRectMake(0.0f, 0.0f - self.tableView.bounds.size.height, self.view.frame.size.width, self.tableView.bounds.size.height)];
view.delegate = self;
[self.tableView addSubview:view];
_refreshHeaderView = view;
[view release];
}
// update the last update date
[_refreshHeaderView refreshLastUpdatedDate];
}
-(void)viewDidAppear:(BOOL)animated {
HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:HUD];
HUD.delegate = self;
HUD.labelText = #"Updating";
HUD.detailsLabelText = #"Please Wait";
[HUD showWhileExecuting:#selector(updateBoard) onTarget:self withObject:nil animated:YES];
// update the last update date
[_refreshHeaderView refreshLastUpdatedDate];
}
With this setup, my application will refresh tab 2 just fine, assuming that tab 2 was the last tab open before you closed the application. If I switch to tab 1 when I close, upon restarting the app, the notification calls tab 2 first and steals the view out from under my progress hud, so when I try to call the viewDidAppear method, the view is null and the app crashes. I either need to figure out how to implement the notification center better so it doesn't crash the other tab, or a better way overall to just refresh when the app becomes active. Looking forward to a good answer. Thanks in advance.
EDIT
When I run with this setup, it aborts inside the MBProgressHUD
- (id)initWithView:(UIView *)view {
// Let's check if the view is nil (this is a common error when using the windw initializer above)
if (!view) {
[NSException raise:#"MBProgressHUDViewIsNillException"
format:#"The view used in the MBProgressHUD initializer is nil."]; // <-- Aborts on this line, so they know it can happen
}
id me = [self initWithFrame:view.bounds];
// We need to take care of rotation ourselfs if we're adding the HUD to a window
if ([view isKindOfClass:[UIWindow class]]) {
[self setTransformForCurrentOrientation:NO];
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(deviceOrientationDidChange:)
name:UIDeviceOrientationDidChangeNotification object:nil];
return me;
}
Main problem here that notifications are received by all views, whether they will appear or not. Good practice would be to notify only those views which will appear in screen
you can use application delegate's (void)applicationWillEnterForeground:(UIApplication *)application method to handle change in application instead of notification.
if problem is all about refreshing tab that is on screen then keeping track of change in tab in AppDelegate and using that when application enters foreground would be better idea over notification.
Other option is to use viewWillAppear method in tabbarcontroller. When this method gets called, you can refresh current tab.
There really isn't much out there to help answer this question. #Learner gave me an idea that ultimately led to how I resolved this issue.
Since all of the logic I have works, the issue was to prevent the HUD from stealing the view from the other one since they both get called when they respond to the notification event. So in my -becomeActive event for both tabs, I added a check if the selectedIndex was a match for the current tab, if not, no refresh. Worked like a charm.
-(void)becomeActive:(NSNotification *)notification {
// only respond if the selected tab is our current tab
if (self.tabBarController.selectedIndex == 1) { // just set the number to your tab index
[self viewDidAppear:YES];
}
}
Hi i am very new in iPhone/iPad developmet.
In my application on clicking of button in want to show view controller like presentModalViewController and i am able to do that which contains the UITableView with some numbers of values. on selecting particulate row i want to pass values to controller which is behind that controller.
for that i am using apple sample application PhotoPicker code. http://developer.apple.com/library/ios/#samplecode/PhotoPicker/Introduction/Intro.html
But i am not able to understand the what i did wrong in my code.
I am not able to go in the code which is in the MyViewController.m
- (void)didFinishWithCamera
{
[self dismissModalViewControllerAnimated:YES];
//Here is my some logic
}
can any one help me for this...how to call this function from OverlayViewController?
please refer above link and guide me or give me some steps or guide me for the same.
use delegation.
I use something like this in a app I'm writing at the moment:
// MySecretSelectionViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[delegate mySecretSelectionViewController:self didSelectObject:[self objectForIndexPath:indexPath] atIndexPath:indexPath];
}
// MyViewController.m
- (void)mySecretSelectionViewController:(MySecretSelectionViewController *)es didSelectObject:(MySecretObject *)object atIndexPath:(NSIndexPath *)indexPath {
// do something with the selected object
[self dismissModalViewControllerAnimated:YES];
}
- (void)showMySecretSelectionViewController:(id)sender {
MySecretSelectionViewController *vc = ...
vc.delegate = self;
// present ViewController
}
You can also do this with use of NSNotificationCenter.
Inside MyViewController.m:
- (void)viewDidLoad
{
// your code
// Add observers
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didFinishWithCamera) name:#"YourObserverName" object:nil];
}
+ (void)callDidFinishWithCamera
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"YourObserverName" object:nil];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
// your code
}
From OverlayViewController.m:
[MyViewController callDidFinishWithCamera];
Use the above class method to call didFinishWithCamera in MyViewController from OverlayViewController
I want to do a series of things in reaction to the end of certain UITableView animations. For example, I want the table view cell to highlight (via selectRowAtIndexPath) after it has been scrolled to via scrollToRowAtIndexPath.
How can this be done?
Basic template:
[UIView animateWithDuration:0.2 animations:^{
//do some animations, call them with animated:NO
} completion:^(BOOL finished){
//Do something after animations finished
}];
Example: Scroll to row 100. When finished, get the cell at this row and make the cell content view with tag=1 to the firstResponder:
[UIView animateWithDuration:0.2 animations:^{
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:100 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
} completion:^(BOOL finished){
//Do something after scrollToRowAtIndexPath finished, e.g.:
UITableViewCell *nextCell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:100 inSection:0]];
[[nextCell.contentView viewWithTag:1] becomeFirstResponder];
}];
I realize this an old post but I was having a similar problem and created a solution that worked well for me. I applied the techniques used on NSCookBook for creating UIAlertViews with blocks. The reason I went for this was because I wanted to use the built-in animations rather than UIView's + animateWithDuration:animations:completion:. There is a larger difference between these animations with the change to iOS 7.
You create a category for UITableView and in the implementation file you create an inner private class that will callback the block by assigning it as your tableview's delegate. The catch is that until the block is called, the original delegate will be "lost" so to speak, since the new delegate is the object that will call the block. That is why I put a notification to send a message when the block has been called to reassign the original UITableViewDelegate. This code has been tested and is working on my end.
// Header file
#interface UITableView (ScrollDelegateBlock)
-(void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath
atScrollPosition:(UITableViewScrollPosition)scrollPosition
animated:(BOOL)animated
scrollFinished:(void (^)())scrollFinished;
#end
// Implementation file
#import "UITableView+ScrollDelegateBlock.h"
#import <objc/runtime.h>
NSString *const BLOCK_CALLED_NOTIFICATION = #"BlockCalled";
#interface ScrollDelegateWrapper : NSObject <UITableViewDelegate>
#property (copy) void(^scrollFinishedBlock)();
#end
#implementation ScrollDelegateWrapper
-(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
if (self.scrollFinishedBlock) {
[[NSNotificationCenter defaultCenter] postNotificationName:BLOCK_CALLED_NOTIFICATION object:nil];
self.scrollFinishedBlock();
}
}
#end
static const char kScrollDelegateWrapper;
static id<UITableViewDelegate>previousDelegate;
#implementation UITableView (ScrollDelegateBlock)
-(void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath
atScrollPosition:(UITableViewScrollPosition)scrollPosition
animated:(BOOL)animated
scrollFinished:(void (^)())scrollFinished {
previousDelegate = self.delegate;
ScrollDelegateWrapper *scrollDelegateWrapper = [[ScrollDelegateWrapper alloc] init];
scrollDelegateWrapper.scrollFinishedBlock = scrollFinished;
self.delegate = scrollDelegateWrapper;
objc_setAssociatedObject(self, &kScrollDelegateWrapper, scrollDelegateWrapper, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[self scrollToRowAtIndexPath:indexPath atScrollPosition:scrollPosition animated:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(blockCalled:)
name:BLOCK_CALLED_NOTIFICATION
object:nil];
}
/*
* Assigns delegate back to the original delegate
*/
-(void) blockCalled:(NSNotification *)notification {
self.delegate = previousDelegate;
[[NSNotificationCenter defaultCenter] removeObserver:self
name:BLOCK_CALLED_NOTIFICATION
object:nil];
}
#end
You can then call the method like any other with a block:
[self.tableView scrollToRowAtIndexPath:self.currentPath
atScrollPosition:UITableViewScrollPositionMiddle
animated:YES
scrollFinished:^{
NSLog(#"scrollFinished");
}
];
Well if you want to perform an action once the scrollToRowAtIndexPath has been fired.
- (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated
You need to create a CAAnimation pointer like
CAAnimation *myAnimation;
Then set the delgate to self
myAnimation.delegate = self;
Once you do that, these following delegate methods should activate where you can put your code:
- (void)animationDidStart:(CAAnimation *)theAnimation
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag