How to verify method was called - ios

I want to test a certain method was called in response to an NSNotification being received
i've tried this:
_sut = mock([EAMainScreenViewController class]);
[_sut view];
[[NSNotificationCenter defaultCenter]postNotificationName:kNotificationPushReceived object:[UIApplication sharedApplication].delegate userInfo:nil];
[verify(_sut) pushReceived:anything()];
And my _sut viewDidLoad looks like this
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(pushReceived:) name:kNotificationPushReceived object:[UIApplication sharedApplication].delegate];
}
why does my test fail expecting 1 invocation, and receiving 0 invocations ?
btw, if i debug - the debugger does stop at the method

You should re-write your test to next:
- (void)setUp {
_sut = [[EAMainScreenViewController alloc] <properInit>];
}
- (void)tearDown {
//just in case
[[NSNotificationCenter defaultCenter] removeObserver:_sut];
}
- (void)testThatNotificationPushReceived {
[_sut viewDidLoad];
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationPushReceived object:<probably some mock> userInfo:nil];
//test something that happens with your mock
}

Related

The NSNotificationCenter is never executed

This is my code.
Here create the observer to Notification called Example into ViewController
- (void)addObserverExample
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(example:)
name:#"Example"
object:nil];
}
- (void)example:(NSNotification *)notification{
NSLog(#"Example!!!");
}
From viewDidLoad register my observer
- (void)viewDidLoad
{
[self addObserverExample];
}
In my second ViewController. When tapped a button excute this code:
[[NSNotificationCenter defaultCenter] postNotificationName:#"Example" object:self.dictKeys userInfo:nil];
The problem I have is that the notification is never executed.
Any idea.
Have created demo for NSNotificationCenter as per your question and it's working fine for me. Here it is the link of that code: NSNotificationCenter Demo
- (void)viewDidLoad {
[super viewDidLoad];
[self addObserverExample];
}
- (void)addObserverExample
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(example:)
name:#"Example"
object:nil];
}
- (void)example:(NSNotification *)notification{
NSLog(#"Example!!!");
NSLog(#"%#",notification.userInfo);
}
- (IBAction)btnFireNotification:(id)sender {
[[NSNotificationCenter defaultCenter] postNotificationName:#"Example" object:nil userInfo:#{#"key" : #"value"}];
}
I believe the problem you're having may be related to the fact that in your second view controller, you're passing self.dictKeys in the object parameter.
If you want to pass data via the NSNotificationCenter, you should use the userInfo parameter instead.
Darshan's example does this the correct way.

iOS Exception of adding NSNotificationCenter to a UIView

I added a NSNotificationCenter to a UIView, when I first go to the page, the NSNotificationCenter work fine.
However, when I left that page and back to that page again, it will give out error
'NSInvalidArgumentException', reason: '-[UITextMagnifierTimeWeightedPoint updateProfile:]: unrecognized selector sent to instance.
Here are the code.
UIView1 :
- (void)changeUIView {
UIView2 *view = [[UIView2 alloc] init];
// show UIView2
}
UIView2 :
- (id)init {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(updateProfile:) name:#"updateProfile" object:nil];
return self;
}
-(void)updateProfile:(NSNotification *)notification {
// do something
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:#"updateProfile"];
}
- (void)buttonClick {
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateProfile" object:nil userInfo:nil];
}
You need to remove self as the observer not the selector you are using to handle the notification
[[NSNotificationCenter defaultCenter] removeObserver:self];
Or if you want to be specific you can use
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"updateProfile" object:nil];
Always
Add NSNotificationCenter in viewDidAppear
And
Remove NSNotificationCenter in viewDidDisAppear

UIKeyboard notification handler triggered 3 times

My code:
-(void)viewWillAppear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleKeyboard:) name:UIKeyboardWillChangeFrameNotification object:nil];
}
-(void)viewWillDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
-(void)handleKeyboard:(NSNotification*)notification {
NSLog(#"triggered");
}
See:
The disappearing handler is triggered once as normal, but 3 times when appears. Is this a iOS bug?
Possibly not helpful for your problem but you need to be calling [super viewWill… for your overrides.
-(void)viewWillAppear:(BOOL)animated
-(void)viewWillDisappear:(BOOL)animated
From the docs.
If you override this method, you must call super at some point in
your implementation.

Need to call removeObserver twice

I have a view that observe values of itself on init like this :
[self addObserver:self forKeyPath:#"focusPointOfInterestIndicator" options:0 context:kSRCameraViewObserverContext];
[self addObserver:self forKeyPath:#"exposurePointOfInterestIndicator" options:0 context:kSRCameraViewObserverContext];
[self addObserver:self forKeyPath:#"paused" options:0 context:kSRCameraViewObserverContext];
[self addObserver:self forKeyPath:#"previewLayerGravity" options:0 context:kSRCameraViewObserverContext];
And on dealloc, observers are removed as they should be like this :
[self removeObserver:self forKeyPath:#"focusPointOfInterestIndicator"];
[self removeObserver:self forKeyPath:#"exposurePointOfInterestIndicator"];
[self removeObserver:self forKeyPath:#"paused"];
[self removeObserver:self forKeyPath:#"previewLayerGravity"];
But unless calling it twice (with or without context, doesn't change anything), I have a crash when the view is deallocated cause the value are still observed.
But I'm quite sure observers are added only once (since it's in init of object).
I just wonder if why it could be registered twice ? Or is it like by calling it twice, it let to the object to effectively remove observers ? If someone have any clue ?
init is the primary initializer of NSObjet that means init must be called in Apple's implementation of initWithCoder / initWithFrame with something like [super init];
so your sharedSetup is called twice
EDIT (thanks to And Ainu):
To be more specific, that's the init method of UIView which calls the initWithFrame method.
Its good practice if you use try catch every time you remove the observer.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
#try {
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"LocationSelected" object:nil];
} #catch (id anException){
//do nothing, obviously it wasn't attached because an exception was thrown
}
[[NSNotificationCenter defaultCenter] addObserverForName:#"LocationSelected" object:nil queue:[NSOperationQueue mainQueue] usingBlock: ^(NSNotification *not) {
//Someone posted the notification handle it here
}];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
#try {
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"LocationSelected" object:nil];
} #catch (id anException){
//do nothing, obviously it wasn't attached because an exception was thrown
}
}
One more thing you can do is instead of observing in init method replace the same in loadView or awakeFromNib method. Then it will not called twice.

Passing data from 3 classes to one another in Objective C

I am unable to pass variables between 3 views in Objective C. I can pass data from one class to another as long as there are just 2, but if I add another view that needs to access the same delegate method, I am unable to do so.
Let me try to explain:
View1 accesses the delegate method declared in View2. However if I add another view called View3 and need to access delegate method for in View2, I cannot. I declared everything correctly and I am able to reference the delegate method, but still I cannot enter that reference in View3.
Two objects can not be both the delegate of a third. Is that your issue? If so, consider using NSNotification in order to send messages: several objects can subscribe to notifications.
if you want to passing data from 1 class to 3 classes , you had better use NSNotification.
you can use like this.
in the first receive class:
#implementation TestClass1
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (id) init
{
self = [super init];
if (!self) return nil;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotification1:)
name:#"TestNotification"
object:nil];
return self;
}
- (void) receiveNotification1:(NSNotification *) notification
{
NSLog(#"receive 1");
}
#end
in the 2nd receive class:
#implementation TestClass2
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (id) init
{
self = [super init];
if (!self) return nil;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotification2:)
name:#"TestNotification"
object:nil];
return self;
}
- (void) receiveNotification2:(NSNotification *) notification
{
NSLog(#"receive 2");
}
#end
in the 3rd receive class:
#implementation TestClass3
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (id) init
{
self = [super init];
if (!self) return nil;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotification3:)
name:#"TestNotification"
object:nil];
return self;
}
- (void) receiveNotification3:(NSNotification *) notification
{
NSLog(#"receive 3");
}
#end
in the post class:
- (void) yourMethod
{
[[NSNotificationCenter defaultCenter]
postNotificationName:#"TestNotification"
object:self];
}

Resources