pass NSString variable to other class with NSNotification - objective-c

I want to pass a NSString from one class to another class and add that NSString to an NSMutableArray in my second class. I'm believe i can use NSNotification for this, but i don't know how to pass an variable over notification. My code would something like this:
//class1.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property(strong,nonatomic)NSString *variableString;
#end
//class1.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize variableString = _variableString;
- (void)viewDidLoad
{
[super viewDidLoad];
[self setVariableString:#"test"];
[[NSNotificationCenter defaultCenter] postNotificationName: #"pasteString" object: _variableString];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
#end
//class2.h
#import <UIKit/UIKit.h>
#interface ViewController2 : UIViewController
#property(strong,nonatomic)NSMutableArray *arr;
#end
//class2.m
#import "ViewController2.h"
#interface ViewController2 ()
#end
#implementation ViewController2
#synthesize arr = _arr;
- (void)viewDidLoad:(BOOL)animated
{
[super viewDidLoad];
if(_arr == nil)
{
_arr = [[NSMutableArray alloc]init];
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(incomingNotification:) name:#"pasteString" object:nil];
// Do any additional setup after loading the view.
}
- (void) incomingNotification:(NSNotification *)notification{
NSString *theString = [notification object];
[_arr addObject:theString];
}
#end

In sender class you can post a notification with an object with something like this:
[[NSNotificationCenter defaultCenter] postNotificationName: NOTIFICATION_NAME object: myString];
The listener or receiver class has to register for the notification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(incomingNotification:) name:NOTIFICATION_NAME object:nil];
The method incomingNotification is:
- (void) incomingNotification:(NSNotification *)notification{
NSString *theString = [notification object];
...
}
EDIT
When you post the notification from "ViewController", is "ViewController2" loaded?

Send your Notification like this:
if(isComingFromHowToUseThisApp) {
[[NSNotificationCenter defaultCenter] postNotificationName:#"noteFromVideoPlayer"
object:#"fromHowToUseThisApp"];
}else {
[[NSNotificationCenter defaultCenter] postNotificationName:#"noteFromVideoPlayer"
object:#"fromVideoPlayerViewiPad"];
}
Receive your notification like this:
// Reset the default value of table view in master split view
- (void)defaultCellSelectionOfTableView:(NSNotification *) objNotification {
// We need to change the default selection of row
NSString *noticeFromVideoPlayer = [objNotification object];
}// end defaultCellSelectionOfTableView

Related

NSNotification not being received in another class

I'm trying to send a notification from one class to another, but notificationReceived never gets called.
AppDelegate:
#import <Cocoa/Cocoa.h>
#import "TestManager.h"
#interface AppDelegate : NSObject <NSApplicationDelegate>
#end
------------------------------
#import "AppDelegate.h"
#interface AppDelegate ()
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSLog(#"did finish launching");
[[TestManager alloc] init];
}
#end
Manager:
#import <AppKit/AppKit.h>
#import "TestObserver.h"
#interface TestManager : NSObject
#end
------------------------------
#import "TestManager.h"
#implementation TestManager
- (instancetype)init {
self = [super init];
if (self) {
NSLog(#"manager init");
[[TestObserver alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(notificationReceived) name:#"testnotification" object:nil];
}
return self;
}
- (void)notificationReceived {
NSLog(#"notification received");
}
#end
Observer:
#import <AppKit/AppKit.h>
#interface TestObserver : NSObject
#end
------------------------------
#import "TestObserver.h"
#implementation TestObserver
- (instancetype)init {
self = [super init];
if (self) {
NSLog(#"observer init");
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(sendNotification) userInfo:nil repeats:YES];
}
return self;
}
- (void)sendNotification {
NSLog(#"observer post");
[[NSNotificationCenter defaultCenter] postNotificationName:#"testnotification" object:nil];
}
#end
Both TestManager and TestObserver need to be a property/ivar, or else either one is deallocated too early.

Object with callback block destroyed after init

I have such a helper class.
#interface CustomOnScreenshot : NSObject;
#property (copy) void (^finishedCallback)(id sender);
-(instancetype)initWithCallback: (void (^)(id sender))callback;
+(instancetype)onScreenshot:(void (^)(id sender))callback;
#end
#implementation CustomOnScreenshot
-(instancetype)initWithCallback: (void (^)(id sender))callback{
self = [super init];
if (self) {
self.finishedCallback = callback;
[self subscribeEvent];
}
return self;
}
+(instancetype)onScreenshot:(void (^)(id sender))callback{
CustomOnScreenshot * onScreenShot = [self new];
[onScreenShot setFinishedCallback:callback];
return onScreenShot;
}
-(void)subscribeEvent{
NSLog(#"CustomOnScreenshot subscribeEvent");
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(doOnScreenShot:) name:UIApplicationUserDidTakeScreenshotNotification object:nil];
}
-(void)unsubscribeEvent{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationUserDidTakeScreenshotNotification object:nil];
}
-(void)doOnScreenShot: (id)sender{
if (self.finishedCallback) {
self.finishedCallback(sender);
}
}
-(void)dealloc{
NSLog(#"CustomOnScreenshot dealloc");
[self unsubscribeEvent];
}
The problem is that if you use it as intended, then the object is immediately destroyed
- (void)viewDidLoad {
[super viewDidLoad];
[CustomOnScreenshot onScreenshot:^(id sender) {
// CUSTOM code
}];
}
Log:
CustomOnScreenshot subscribeEvent
CustomOnScreenshot dealloc
All works only when I use the result in property, but I find this excessive
#property (strong, nonatomic) CustomOnScreenshot * customOnScreenshot;
- (void)viewDidLoad {
[super viewDidLoad];
self.customOnScreenshot = [CustomOnScreenshot onScreenshot:^(id sender) {
// CUSTOM code
}];
}
If you don't have a strong reference to the CustomOnScreenshot instance, then the object will be deallocated by ARC as as soon as +onScreenshot: finishes execution.
That's why the #property fixes it.
If you don't want an #property, then I'd suggest a singleton.

Capture Key Presses In Many GKState Classes

I'm using SpriteKit in Objective C for Mac OS. I'm a noob when it comes to working with NSNotification, but I used the following method in another app I was working on, but it's now not working. Perhaps there's a better method, but I want to be able to capture key presses based on what state the app is in.
The Main Issue
The state begins in GameBeginState. Once the spacebar is pressed, it moves into GamePlayState. If I press any other keys, it shows that it's using the keyPressed: method from GameBeginState as opposed to the keyPressed method in GamePlayState. Any ideas why? I can't figure this out for the life of me.
Details
I created a custom view called CustomNotificationHandler and set my main SKView in the project.
Here's the code for CustomNotificationHandler:
CustomNotificationHandler
#import "CustomNotificationHandler.h"
#implementation CustomNotificationHandler:SKView {
// Add instance variables here
}
- (id) initWithCoder:(NSCoder *)coder {
self = [super initWithCoder:coder];
if (self) {
// Allocate and initialize your instance variables here
}
return self;
}
- (void) keyDown:(NSEvent *)theEvent {
[[NSNotificationCenter defaultCenter] postNotificationName:#"KeyPressedNotificationKey"
object:nil
userInfo:#{#"keyCode" : #(theEvent.keyCode)}];
}
#end
In my main class GameScene I have a GKStateMachine set up that initializes 3 states. The classes for the states are below:
GamePlayState.m
#import "GameReadyState.h"
#import "GamePlayState.h"
#interface GameReadyState()
#property (weak) GameScene *scene;
#end
#implementation GameReadyState
-(instancetype) initWithScene:(GameScene*)scene {
if (self = [super init]) {
self.scene = scene;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyPressed:) name:#"KeyPressedNotificationKey" object:nil];
}
return self;
}
-(void) didEnterWithPreviousState:(GKState *)previousState {
}
-(void) willExitWithNextState:(GKState *)nextState {
}
-(BOOL) isValidNextState:(Class)stateClass {
return stateClass == [GamePlayState class];
}
-(void)keyPressed:(NSNotification*)notification {
NSNumber *keyCodeObject = notification.userInfo[#"keyCode"];
NSInteger keyCode = keyCodeObject.integerValue;
NSLog(#"GAME READY key = %ld", (long)keyCode);
switch (keyCode) {
case 49:
[self.stateMachine enterState:[GamePlayState class]];
break;
default:
break;
}
}
#end
Here's the 2nd state...pretty much the same as the 1st:
GamePlayState
#import "GamePlayState.h"
#import "GamePauseState.h"
#interface GamePlayState()
#property (weak) GameScene *scene;
#end
#implementation GamePlayState
-(instancetype) initWithScene:(GameScene*)scene {
if (self = [super init]) {
self.scene = scene;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyPressed:) name:#"KeyPressedNotificationKey" object:nil];
}
return self;
}
-(void) didEnterWithPreviousState:(GKState *)previousState {
[_scene setPaused:NO];
}
-(BOOL) isValidNextState:(Class)stateClass {
return stateClass == [GamePauseState class];
}
-(void) updateWithDeltaTime:(NSTimeInterval)seconds {
[_scene.sequence moveLeft];
}
-(void)keyPressed:(NSNotification*)notification {
NSNumber *keyCodeObject = notification.userInfo[#"keyCode"];
NSInteger keyCode = keyCodeObject.integerValue;
NSLog(#"GAME PLAY key = %ld", (long)keyCode);
switch (keyCode) {
case 53:
[self.stateMachine enterState:[GamePauseState class]];
[_scene setPaused:YES];
break;
default:
break;
}
}
#end

NSNotificationCenter get notifications on NSMutableDictionary addObject

How can I get notifications with NSNotificationCenter when object is added to NSMutableDictionary?
Also are there any notifications for immutable NSDictionary?
The the beauty of inheritance :)
#define kSomeDictionarySetAValue #"SomeDictionarySetAValue"
#interface SomeDictionary : NSMutableDictionary
#end
#implementation SomeDictionary
- (void) setValue:(id)value forKey:(NSString *)key
{
[super setValue:value forKey:key];
[[NSNotificationCenter defaultCenter] postNotificationName:kSomeDictionarySetAValue
object:self];
}
#end

Can an object subscribe to its own notifications?

For example, a UITextField cannot be its own delegate, but is it OK to just have it register itself as an observer of its own notifications? Looks weird but seems to work fine. Thoughts?
// MyTextField.h
#interface MyTextField : UITextField
#end
// MyTextField.m
#interface MyTextField ()
- (void)myTextFieldDidChange:(NSNotification *)notification;
#end
#implementation MyTextField
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(myTextFieldDidChange:)
name:UITextFieldTextDidChangeNotification
object:self];
}
}
- (void)myTextFieldDidChange:(NSNotification *)notification {
// Do custom stuff here.
}
#end
What you're doing seems fine, but there's a purer solution for this particular example:
// MyTextField.h
#interface MyTextField : UITextField
#end
// MyTextField.m
#interface MyTextField ()
- (void)myTextFieldDidChange:(UITextField *)textField;
#end
#implementation MyTextField
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self addTarget:self action:#selector(myTextFieldDidChange:)
forControlEvents:UIControlEventEditingChanged];
}
return self;
}
- (void)myTextFieldDidChange:(MyTextField *)myTextField {
// Do custom stuff here.
}
#end
Check out the UIControlEvents reference.