How to run method from another class - objective-c

In TabBarViewController class, I have startUpdateNPendingMessagesTimer method which run a NSTimer
I have also timerStop to stop this NSTimer with invalidate method
-(void)startUpdateNPendingMessagesTimer {
NSLog(#"Starting UpdateNPendingMessagesTimer");
checkNPendingMessagesTimer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:#selector(onUpdateNPendingMessages:) userInfo:nil repeats:YES];
}
-(void)timerStop
{
[checkNPendingMessagesTimer invalidate];
checkNPendingMessagesTimer = nil;
}
In another class settingsViewController, I have a button, which actually have to activate the timerStop method.
-(IBAction)deconnexion { ....
}
What should I write in the button action to activate the timerStop method ?
In other words, how to activate a method from another class in objective C ?

There are a bunch of options:
Notification via Notification center
Lambda callback (in objc terms it's called "block") - pass it to your object that runs timer and store it. Invoke it when appropriate
use the omnipresent (in cocoa) pattern of Delegation - create a delegate object and pass it to your timer-containing class. Call methods of this object when appropriate.
I'd go with block/lambda, as it is clean, efficient, has less overhead than other solutions and saves typing (yay!).

You can use the Notification Center to communicate between two unrelated classes.
First in your ViewDidLoad of your TabBarViewController class register to a specific notification (identified by a "name") with the code below:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(timerStop)
name:#"aNameOfaNotification"
object:nil];
Then in your "deconnexion" method you just need to post a notification of the same name:
[[NSNotificationCenter defaultCenter] postNotificationName:#"aNameOfaNotification"
object:nil];
Every class who observe that Notification Name will fire the local method specified in the selector: argument, in this case: timerStop.
Be careful if you are not using ARC, you may also need to unregister your TabBarViewController class when it is discarded by adding the following code in this class:
-(void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
(You can also use: viewWillAppear / viewWillDisappear for your addObserver/removeObserver code)
Bonne chance!

Related

Setting UIScrollView's Position from another ViewController

I am trying to set the position of a UIScrollView by using contentOffset as such:
- (void) navigateToTableViewPosition:(CGPoint)contentOffset {
NSLog(#"Position set method gets called...");
NSLog(#"%#", NSStringFromCGPoint(contentOffset));
[mainScrollView setContentOffset:contentOffset animated:YES];
}
I call this method from another view controller before I dismiss it, and everything checks out. I pass the argument correctly, and the method gets called (checked it with NSLog), but the scroll view does not move...
What is funny is that when I call this method from the view controller, in which it is located, it works fine. Only when I call it from another view controller, it stops working.
Just for future reference, here is the calling method:
MainViewController *mainView = [[MainViewController alloc] init];
[mainView navigateToTableViewPosition:contentOffset];
Content offset is a CGPoint I set beforehand. It doesn't matter here; besides, it gets passed correctly anyways.
Try this, You have to send notification from other viewcontroller when you want to change ..
[[NSNotificationCenter defaultCenter] postNotificationName:#"changepostion" object:NSStringFromCGPoint(CGPointMake(contentOffset.x, contentOffset.y))];
in mainviewcontroller
-(void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(navigateToTableViewPosition:) name:#"changepostion" object:nil];
}
- (void) navigateToTableViewPosition:(NSNotification *)notification
{
contentOffset =CGPointFromString([notification object]);
NSLog(#"Position set method gets called...");
NSLog(#"%#", NSStringFromCGPoint(contentOffset));
[mainScrollView setContentOffset:contentOffset animated:YES];
}
You can't set the properties of a view which is not visible. If you are using iOS5+ you can implement the offset setting in the completion in the view dismiss completion block.
Use delegate for backward messaging in view controllers.
Refer Basic Delegate Example link for more reference.
Your are making new instance of viewcontroller which will call method but will have no effect.

NSWindow event when change size of window

what is method call when change size in Window?
I find somesing aboud windowDidResize: so i try doing
- (void)windowDidResize:(NSNotification *)notification {
NSLog(#"test");
}
I found what need use NSWindowDidResizeNotification, but I work for the first time with NSNotification and bad understand about this.
Can somebody write a full example for my event, please?
The -windowDidResize: method is called on the window delegate. Is the object with the method you posted the delegate for the window?
For something other than the delegate, you can do:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(windowDidResize:) name:NSWindowDidResizeNotification object:theWindow];
and, when the observer is no longer interested or being deallocated:
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidResizeNotification object:theWindow];
Another approach is to use the new block-based API to NSNotificationCenter:
id observation = [[NSNotificationCenter defaultCenter] addObserverForName:NSWindowDidResizeNotification object:theWindow queue:nil usingBlock:^(NSNotification *){
NSLog(#"test");
}];
// store/retain the observation for as long as you're interested in it. When it's deallocated, you stop observing.
You can Implement NSWindowDelegate:
class YourVC: NSWindowDelegate {
// This method trigger when you press the resize button in the window toolbar
func windowDidResize(_ notification: Notification) {
// Write your code here
}
}
And, In viewDidLoad() or viewDidAppear() method
self.view.window?.delegate = self
You can also use other delegate methods:
windowDidEnterFullScreen
windowDidExitFullScreen
...

Is it possible to monitor other application using Cocoa on Mac?

For example, get the notification that another Application is becoming Active on the screen, or resign active state.
Sure. In your app delegate class, you can use NSWorkspace to get notified when an app becomes active (NSWorkspaceDidActivateApplicationNotification) or resigns active (NSWorkspaceDidDeactivateApplicationNotification). See the documentation on NSWorkspace for more info.
In your controller class, you'd do something like this:
- (id)init {
if ((self = [super init])) {
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
selector:#selector(appDidActivate:)
name:NSWorkspaceDidActivateApplicationNotification
object:nil];
}
return self;
}
- (void)dealloc {
[[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
[super dealloc];
}
- (void)appDidActivate:(NSNotification *)notification {
NSDictionary *userInfo = [notification userInfo];
NSLog(#"userInfo == %#", userInfo);
}
The key points are basically that you need to register to receive the notifications like shown in -init. You'd repeat the code to add another observer for each additional notification name that you want (e.g NSWorkspaceDidDeactivateApplicationNotification).
Another important thing to remember is to remove yourself as an observer in -dealloc (or elsewhere), so that NSWorkspace doesn't try to notify your controller object after it's been released+dealloc'd (and would no longer be valid).
In the specified -appDidActivate: method, do whatever you need to with the info about the app in question.
If you want something simpler than distributed objects, you could use distributed notifications from the distributed notification center. However, these are not posted unless you built the application. For monitoring when applications start or quit, you can use NSWorkspace and its notification center (suggested by NSGod)

How to call a selector in a different class?

I'm trying to use this code but Xcode returns an error because the method I'm trying to call in the selector:#selector() is in another class. Thanks for your help!
AppDelegate.m:
-(void)applicationDidBecomeActive:(UIApplication *)application{
[..]
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(myMethodHere) name:UIApplicationDidBecomeActiveNotification object:nil];
}
MainViewController.m:
-(void)myMethodHere{
[..]
}
The problem is that you use
addObserver:self
which means that it looks for the function in the current class. Instead do something like
addObserver:instanceOfOtherClass
Update
Add the call to the init method of MainViewController
// MainViewController.m
- (id)init;
{
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(someMethod) name:UIApplicationDidBecomeActiveNotification object:nil];
}
return self;
}
Make sure to remove yourself in dealloc
- (void)dealloc;
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
By doing it this way from the very moment the object comes in to existence it is ready to receive notifications and then when it is being deallocated it will safely remove itself.
A good pattern to follow is to make the class that is doing the observing responsible for registering for notifications. This keeps encapsulation well and removes some risk of sending notification to deallocated instances.
Rationale
You need to balance your calls for registering for notifications and unregistering for notifications otherwise a message may be called on a deallocated object which could be hard to track down.
If I have a class that needs to be notified of an event the likely hood is I will register for the notifications in the init method and then unregister for the notifications in the dealloc (init and dealloc are just examples of times I often do this, not necessarily the best place in every example, do what makes sense in your case).
The issue is your use of
addObserver:self
The observer needs to be an instance class that contains the method you want to call, so create that first and then add the notification. Something like.
-(void)applicationDidBecomeActive:(UIApplication *)application{
[..]
SomeClass *newObject = [[SomeClass alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:newObject selector:#selector(someMethodContainedInSomeclass) name:UIApplicationDidBecomeActiveNotification object:nil];
}

NSNotificationCenter Scope definition

So I'm new to NSNotifications, I am wondering what the scope is. I.e. If I have an Application Delegate Class, and it is the receiver of a notification:
-(id)init
{
[ super init];
if (!self) return nil;
// Add to our notification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveUpdateRequest:)
name:#"RequestStatusUpdate"
object:nil];
return self;
}
And has this method run on receive:
- (void) receiveUpdateRequest:(NSNotification *) notification
{
// Check the Notification Name
if ([[notification name] isEqualToString:#"RequestStatusUpdate"]){
NSLog (#"Recieved Update Status!");
}
else {
NSLog(#"Recieved Notification: %#",[notification name]);
}
}
Can I post a notification like so:
[[NSNotificationCenter defaultCenter] postNotificationName:#"RequestStatusUpdate" object:self];
From another object instance any where in my App?
Even for instance an object that instantiated by virtue of a NIB being loaded:
summaryWindow = [[SummaryWindowController alloc] initWithWindowNibName:#"SummaryWindow" owner:globalStatusController];
Do I have to have anything else configured in my summaryWindow Class to be able to call the postNotificationName method.
Or put a different way is the [NSNotificationCenter defaultCenter] global for all instances of all objects in my Application, I would assume thats how its suppose to work but currently when I call this method via an IBAction in my SummaryWindow , the notification does not seemed to be received.
I have tested both [NSThread currentThread] and the default Notification center and it does look like I'm in the thread and the same notification center ( which I think is always global). I am only looking into the thread thing as its come up on a few other threads.
2011-08-22 20:57:11.452 AppName[23102:1307] Using Default Notification Center: <CFNotificationCenter 0x10012c900 [0x7fff7d302ea0]>
2011-08-22 20:57:20.366 AppName[23102:1307] Using Default Notification Center: <CFNotificationCenter 0x10012c900 [0x7fff7d302ea0]>
Wow that was lame, I just found [[NSNotificationCenter defaultCenter] removeObserver:self]; in some earlier code. I had it in dealloc but some how managed to miss it in another NSTask method I was working on.
Or put a different way is the [NSNotificationCenter defaultCenter] global for all instances of all objects in my Application
Yes.
I would assume thats how its suppose to work but currently when I call this method via an IBAction in my SummaryWindow , the notification does not seemed to be received.
That's because you're registering in init. I'm betting this is Mac, and on Mac the application delegate is almost always instantiated from a nib file. You need to do this work in awakeFromNib.
Note that you generally do not need to check the notification's name. It's generally best to have a different method for each notification callback. You should also always create a string constant for your notification names. It's way too easy to mis-type them.