Delete An NSMutableArray from another Class in C-Objective? - objective-c

I need help with delete an array with a button from the SecondViewController in the view controller class.
At the moment I have this:
- (IBAction)deleteArrayFromSeconViewController:(id)sender // is the Button which should
// delete the array
{
self.textLabel2.text = #""; // this work fine
ViewController *vc = [[ViewController alloc]init];
[vc.textViewArray removeAllObjects]; // do not remove the objects?
}
What should I do to overtake an order from the SecondViewControllerClass in the ViewControllerClass?
I tried also this in the SecondViewControllerClass:
- (IBAction)deleteArrayFromSeconViewController:(id)sender
{
self.textLabel2.text = #"";
ViewController *vc = [[ViewController alloc]init];
[vc deleteTheArray];
}
to call this function in the ViewControllerClass:
- (void) deleteTheArray
{
[textViewArray removeAllObjects];
}

I'm not at all sure that this is the best way to do this, but you could post a custom NSNotification in your first view controller, and then pick it up in your second. Code Example:
//Post in your first view controller when wanting to delete the array
[[NSNotificationCenter defaultCenter] postNotificationName:#"DeleteArrayNotification" object:nil userInfo:nil /*include any items your reciever might wish to access*/];
and then in your second view controller, you could add yourself as an observer in the -(void)awakeFromNib Method. Put in your awake from nib method:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(deleteArrayNotification:) name:#"DeleteArrayNotification" object:nil];
And then implement the deleteArrayNotification: method:
- (void)deleteArrayNotification:(NSNotification *)notification {
[array removeAllObjects];
[array release]; //Delete this line if your project is using ARC
}
I am highly doubtful that this is good coding practice to implement NSNotification like this, but I thought it might be of use!
More information can be found under the Apple developer documentation, under NSNotification and NSNotificationCenter.
Hope I can help!
Ben

Related

nsnotification approach for session inactivity in objective c

In sesssion inactivity implementation for my project. I have created a NSNotification in RootViewController class of project.
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle: #"Close"
style: UIBarButtonItemStyleDone
target: self
action: #selector(closeModal)];
UIImage *image = [UIImage imageNamed:#"fidelity_logotype"];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
[imageView setImage:image];
[self.navigationItem setTitleView:imageView];
self.navigationController.view.backgroundColor = [UIColor fidelityGreen];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationDidTimeout:) name:#"ApplicationTimeout" object:nil];
}
- (void) applicationDidTimeout:(NSNotification *) notif
{
NSLog(#"I m here");
BCDSessionInactivityViewController *sessionView=[[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"InactivityViewController"];
sessionView.modalPresentationStyle = UIModalPresentationFormSheet;
sessionView.preferredContentSize = CGSizeMake(838,340);
[[self topViewController] presentViewController:sessionView animated:YES completion:nil];
}
and in logoutviewcontroller, i am removing this observer written below
- (IBAction)logoutbtn:(id)sender
{
NSLog(#"logout is called");
[sessionTimer invalidate];
sessionTimer = nil;
[[BCDTimeManager sharedTimerInstance]stopIdleTimer];
//[self dismissViewControllerAnimated:YES completion:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"ApplicationTimeout" object:nil];
[self performSegueWithIdentifier:#"Thankyoupage" sender:self];
}
This is code where i posting the notification.
- (void)idleTimerExceeded {
NSLog(#"idle time exceeded");
[[NSNotificationCenter defaultCenter]
postNotificationName:#"ApplicationTimeout" object:nil];
}
for first time login, it works fine whenever timer exceeds, i post a notification and model view is presesnted perfectly, but once user logs out, after that whenever the notification is posted, selector method is getting called twice
I am pretty sure that notification is getting posted only once.
Should i create notification in every view controller and then remove it when view unloads?
what i am doing wrong here?
You are adding the notification in RootViewController and trying to remove it from LogoutViewController. So that notification observer added to the RootViewController never gets removed. So each time you logout and login, the observer call will get increased by one. For fixing the issue, you need to remove the observer from the RootViewController object.
For fixing the issue you mentioned in your comment,
If I remove the observer in RootViewController , then if timers
exceeds in some other views, and notification observer is not called.
Also, i can't add observer on app delegate because we want timer
notification to be fired only after reaching rootviewController
Write two public methods in AppDelegate
One for adding observer (addObserver)
One for removing observer (removeObserver)
When you reach RootViewController, call the addObserver method for adding the observer
When logout is pressed, call the removeObserver for removing the observer

Call pushViewController from external class?

I'm new to IOS7 and i am struggling to call pushViewController.
First i have UINavigationController as a root view controller i have UICollectionViewController.
In this UICollectionViewController i have also register UICollectionViewCell class
[self.collectionView registerClass:[MYProductCell class]
forCellWithReuseIdentifier:#"product"];
I am trying to pushViewController width detail view based on user action in the cell.
I have NO problems by using
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *product = self.products[indexPath.row];
TXDetailProductController *detailView = [[TXDetailProductController alloc] init];
detailView.product = product;
[self.navigationController pushViewController:detailView animated:YES];
}
But I want to call pushViewController:detailView from UICollectionViewCell class based on User action.
Can someone give me directions?
Thanks in advance!
You could send a message.
In your viewDidLoad you could set up a message listener:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(pushDetailView:) name:#"pushDetailView" object:nil];
Then add a method:
-(void) pushDetailView:(id)sender
{
// do your pushViewController
}
Then in your UICollectionViewCell when you need to push the view do:
NSNotification* notification = [NSNotification notificationWithName:#"pushDetailView" object:self];
[[NSNotificationCenter defaultCenter] postNotification:notification];
The listener should receive that notification and call the pushDetailView which will push the view. You might need some error checking in there also.
You might need to pass information to the method so you know what to push. You can put the information in an object and send it with the message. Something like:
NSNumber *indexPathRow = [NSNumber numberWithInt: indexPath.row];
NSNotification* notification = [NSNotification notificationWithName:#"pushDetailView" indexPathRow object:indexPathRow];
[[NSNotificationCenter defaultCenter] postNotification:notification];
Then on the receiver class you pull that info out of the notification's object:
-(void) pushDetailView:(NSNotification*)note
{
NSNumber indexPathRow = [note object];
NSDictionary *product = self.products[[indexPathRow intValue]];
// and on with your pushViewController code
}
Again error checking in there also.

Cocoa: saveAction called 2 times with notification

I have a custom class for NSButton called MyButton where I post a notification for a quicksave
MyButton.m:
-(void)mouseDown:(id)sender{
[super mouseDown:sender];
[super mouseUp:sender];
[[NSNotificationCenter defaultCenter] postNotificationName:#"quickSave" object:nil userInfo:nil];
}
in AppDelegate I get the notification for the quick save:
AppDelegate.m:
- (IBAction)saveAction:(id)sender{
NSLog(#"Saving...");
NSError *error = nil;
if (![[self managedObjectContext] commitEditing]) {
NSLog(#"%#:%# unable to commit editing before saving", [self class], NSStringFromSelector(_cmd));
}
if (![[self managedObjectContext] save:&error]) {
[[NSApplication sharedApplication] presentError:error];
}
}
-(void)awakeFromNib{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(saveAction:) name:#"quickSave" object:nil];
}
Via the NSLog "Saving..." I see that the saveAction is called 2 times. Why?
P.S: the notification calls 2 times every function I insert in the selector: field, so maybe it has to do with the -(void)awakeFromNib{...} because I see that it's called twice (there are two different self inside the awakeFromNib).
UPDATE: I've "solved" the problem binding in Interface Builder the Application as an AppDelegate delegate and then adding the [[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(saveAction:) name:#"quickSave" object:nil]; inside the -(void)applicationDidFinishLaunching:(NSNotification *)aNotification{...}. I don't know if it's a real solution and obviously it is not an answer to my question (why awakeFromNib is called 2 times), but it might be useful to someone. Does anyone have a clue?
UPDATE2: the right managedobjectcontext is the one called in awakeFromNib the second time, the first one (identical in awakeFromNib and applicationDidFinishLaunching) is wrong.
My app is a statusbar app, the first awakeFromNib is called when i start the app and the second one when a preference window is opened.
The log message indicates that two different instances of AppDelegate receive a single notification. Probably you instantiated AppDelegate twice. Ensure you are not manually doing [[AppDelegate alloc] init] or something, and not putting more than one AppDelegate object in NIB.

How do you access a uitableview inside a uinavigationcontroller inside a uitabbarcontroller from app delegate?

Im trying to access a refresh control method in a uitableview which is inside a navigationcontroller from a tabbarcontroller which is my root, but im having trouble getting an exact handle.
This is my code so far in the AppDelegate but it doesn't work...
UITableViewController *tableView = (UITableViewController *)[[self.tabbarController viewControllers][0] tableView];
[tableView.refreshControl beginRefreshing];
I have 5 tab bar items which I believe I can access via [0],[1],[2],[3]
And my code in the UITableView (though probably doesnt matter)...
// Add Refresh Control
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:appDelegate action:#selector(forceDownload) forControlEvents:UIControlEventValueChanged];
self.refreshControl = refreshControl;
[refreshControl release];
Any help would be greatly appreciated as i cant find any online that access as deep as this.
If you need communication between objects that are unrelated, i think that the best option is to use NSNotifications. This allows you to use the singleton object[NSNotificationCenter defaultCenter], to pass notifications from one object to another (or many others).
So you can put the AppDelegate object (or other object) to observe a specific notification and then post the notification with the tableviewController when you need to refresh the control.
In app delegate class you can add the observer like:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(forceDownload)
name:#"ForceDownloadNotification"
object:nil];
And, in the tableviewController you can post de notification like:
[[NSNotificationCenter defaultCenter] postNotificationName:#"ForceDownloadNotification"
object:self];
Here, I used the name "ForceDownloadNotification" as the name for the notification. You can use the name that you want, but in order this solution work properly, you must use the same name when you start the observation and when you post the notification.
Here you have a tutorial about this subject.
I like Luis Espinoza's approach but that doesn't answer the question per se.
If you want to call a method inside your UITableViewController nested inside a UINavigationController which is the rootViewController for your App Delegate. First we create a navigationController with the UITableViewController (or a subclass):
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
CustomTableViewController *nuTableVC = [[CustomTableViewController alloc] initWithStyle:UITableViewStylePlain];
UINavigationController *nuNavController = [[UINavigationController alloc] initWithRootViewController:nuTableVC];
self.window.rootViewController = nuNavController;
[self.window makeKeyAndVisible];
return YES;
}
Then in your UITableViewController (or subclass) you setup the refreshcontrol just like you asked:
- (void)viewDidLoad {
[super viewDidLoad];
// Add Refresh Control
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:[[UIApplication sharedApplication] delegate]
action:#selector(forceDownload)
forControlEvents:UIControlEventValueChanged];
self.refreshControl = refreshControl;
}
Finally to access the UItableViewController you must check if the instances are really the classes that you want, here is my implementation for the method you created (forceDownload) in your App Delegate:
- (void)forceDownload {
NSLog(#"force download method in App Delegate");
UINavigationController *someNavController = (UINavigationController*)[_window rootViewController];
UIViewController *vcInNavController = [[someNavController viewControllers] objectAtIndex:0];
if ([vcInNavController isKindOfClass:[CustomTableViewController class]]) {
NSLog(#"it is my custom Table VC");
NSLog(#"here we can stop the refresh control, or whatever we want");
CustomTableViewController *customTableVC = (CustomTableViewController *)vcInNavController;
[customTableVC.refreshControl performSelector:#selector(endRefreshing)
withObject:nil
afterDelay:1.0f];
}
}
I personally prefer using NSNotificationCenter because is simpler, but that doesn't mean we can't access the objects the way you originally planed.
(if you want the example code just ask for it).
Regards.
If your goal is truely to just keep your refresh control synch'd with the networkActivityIndicator then one option is KVO.
In the viewController's viewDidAppear: add something like this
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
UIApplication *application = [UIApplication sharedApplication];
[application addObserver:self
forKeyPath:#"networkActivityIndicatorVisible"
options:NSKeyValueObservingOptionNew
context:myContext];
self.refreshControl.refreshing = [application isNetworkActivityIndicatorVisible];
}
Then make sure to remove this observer when the viewController doesn't need it - perhaps in viewDidDisappear:
- (void)viewWillDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[[UIApplication sharedApplication] removeObserver:self
forKeyPath:#"networkActivityIndicatorVisible"
context:myContext];
}
Now for the actual work
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
{
if (myContext == context) {
self.refreshControl.refreshing = [change[NSKeyValueChangeNewKey] boolValue];
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}

Can't seem to be able to re alloc a released UIView

I have a UIView which I create programmatically roughly like so:
#implementation SlideShowView
- (id)initWithImages
{
…
if (self=[super initWithFrame:CGRectMake(0, 0, 320, 480)])
{
// init objects here
}
return self;
}
- (void)dealloc
{
printf("dealloc slide show view\n");
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"unlockUI" object:nil ];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"setUserRating" object:nil ];
[mCurrentImageView release];
[mRightImageView release];
[mLeftImageView release];
[mImages release];
[queue cancelAllOperations];
[queue release];
[managingArray release];
[super dealloc];
}
with a uiview controller that contains this:
- (void)loadView {
{
...
self.view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
self.slideShowViewObject = [[SlideShowView alloc] initWithImages];
[self.view addSubview:slideShowViewObject];
…
}
-(void)dealloc
{
[slideShowViewObject release];
[self.slideShowViewObject removeFromSuperview];
printf("dealloc of slideshow view controller\n");
[super dealloc];
}
this seems to be able to dealloc both the view controller and view but when I push this view controller back onto the stack I get the message with zombie enabled: -[SlideShowView retain]: message sent to deallocated instance 0x43ab160
should the alloc not be creating a new instance of the view when the controller is pushed? I don't understand and after spending many hours reading through other posts as well as looking at memory guides I would say I'm thoroughly stumped! Can someone offer any pointers? I only posted the code I deemed necessary but I can post more if need be.
Thanks so much!
First, you shouldn't call both [super init] and [super initWithFrame:], only one of the two in your UIView subclass.
Secondly, you should only set self.view in a view controller in the -loadView method, which is designed for you to create your views. Normally, unless you need to do certain types of setup such as initializing variables, etc, you shouldn't need to override -init in UIViewController subclasses.
finally, after finagling with the code again tonight I finally got it working. The key piece I was not releasing appears to be
[self.view release];
I suppose this makes perfect sense since I was adding the view as a subview of this alloc'd self view, but I had tried this before. Perhaps cleaning up the code is what made it work this time.