Skip to content

Commit 49a9267

Browse files
Notification Listener Changes (#212)
* Notification Listener Changes * example of using notification center. * removed type from addNotification overloads * updated to match the design doc * asserts in send notifications * merge fixes * test cases for NotificationCenter * removed SwiftNotifyTest * property for OPTLYNotificationCenter in OPTLYClient * fix - file reference * Track tests added Copyright updated * convert if to case statement
1 parent 62c0a44 commit 49a9267

File tree

15 files changed

+300
-170
lines changed

15 files changed

+300
-170
lines changed

OptimizelySDKCore/OptimizelySDKCore.xcodeproj/project.pbxproj

Lines changed: 40 additions & 6 deletions
Large diffs are not rendered by default.

OptimizelySDKCore/OptimizelySDKCore/OPTLYNotificationCenter.h

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,28 @@
1717
#import <Foundation/Foundation.h>
1818

1919
@class OPTLYProjectConfig, OPTLYExperiment, OPTLYVariation;
20-
@protocol OPTLYNotificationDelegate;
2120

2221
/// Enum representing notification types.
2322
typedef NS_ENUM(NSUInteger, OPTLYNotificationType) {
2423
OPTLYNotificationTypeActivate,
2524
OPTLYNotificationTypeTrack
2625
};
2726

28-
typedef NSMutableDictionary<NSNumber *, id<OPTLYNotificationDelegate> > OPTLYNotificationHolder;
27+
typedef void (^ActivateListener)(OPTLYExperiment * _Nonnull experiment,
28+
NSString * _Nonnull userId,
29+
NSDictionary<NSString *,NSString *> * _Nonnull attributes,
30+
OPTLYVariation * _Nonnull variation,
31+
NSDictionary<NSString *,NSObject *> * _Nonnull event);
32+
33+
typedef void (^TrackListener)(NSString * _Nonnull eventKey,
34+
NSString * _Nonnull userId,
35+
NSDictionary<NSString *,NSString *> * _Nonnull attributes,
36+
NSDictionary * _Nonnull eventTags,
37+
NSDictionary<NSString *,NSObject *> * _Nonnull event);
38+
39+
typedef void (^GenericListener)(NSArray * _Nonnull args);
40+
41+
typedef NSMutableDictionary<NSNumber *, GenericListener > OPTLYNotificationHolder;
2942

3043
@interface OPTLYNotificationCenter : NSObject
3144

@@ -43,20 +56,18 @@ typedef NSMutableDictionary<NSNumber *, id<OPTLYNotificationDelegate> > OPTLYNot
4356
/**
4457
* Add an activate notification listener to the notification center.
4558
*
46-
* @param type - enum OPTLYNotificationType to add.
4759
* @param activateListener - Notification to add.
4860
* @return the notification id used to remove the notification. It is greater than 0 on success.
4961
*/
50-
- (NSInteger)addNotification:(OPTLYNotificationType)type activateListener:(nonnull id<OPTLYNotificationDelegate>)activateListener;
62+
- (NSInteger)addActivateNotificationListener:(nonnull ActivateListener)activateListener;
5163

5264
/**
5365
* Add a track notification listener to the notification center.
5466
*
55-
* @param type - enum OPTLYNotificationType to add.
5667
* @param trackListener - Notification to add.
5768
* @return the notification id used to remove the notification. It is greater than 0 on success.
5869
*/
59-
- (NSInteger)addNotification:(OPTLYNotificationType)type trackListener:(nonnull id<OPTLYNotificationDelegate>)trackListener;
70+
- (NSInteger)addTrackNotificationListener:(TrackListener _Nonnull )trackListener;
6071

6172
/**
6273
* Remove the notification listener based on the notificationId passed back from addNotification.

OptimizelySDKCore/OptimizelySDKCore/OPTLYNotificationCenter.m

Lines changed: 66 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
#import "OPTLYExperiment.h"
2121
#import "OPTLYVariation.h"
2222
#import <objc/runtime.h>
23-
#import "OPTLYNotificationDelegate.h"
2423

2524
@interface OPTLYNotificationCenter()
2625

@@ -56,16 +55,12 @@ -(NSUInteger)notificationsCount {
5655
return notificationsCount;
5756
}
5857

59-
- (NSInteger)addNotification:(OPTLYNotificationType)type activateListener:(id<OPTLYNotificationDelegate>)activateListener {
60-
if (![self isNotificationTypeValid:type expectedNotificationType:OPTLYNotificationTypeActivate])
61-
return 0;
62-
return [self addNotification:type listener:activateListener];
58+
- (NSInteger)addActivateNotificationListener:(ActivateListener)activateListener {
59+
return [self addNotification:OPTLYNotificationTypeActivate listener:(GenericListener) activateListener];
6360
}
6461

65-
- (NSInteger)addNotification:(OPTLYNotificationType)type trackListener:(id<OPTLYNotificationDelegate>)trackListener {
66-
if (![self isNotificationTypeValid:type expectedNotificationType:OPTLYNotificationTypeTrack])
67-
return 0;
68-
return [self addNotification:type listener:trackListener];
62+
- (NSInteger)addTrackNotificationListener:(TrackListener)trackListener {
63+
return [self addNotification:OPTLYNotificationTypeTrack listener:(GenericListener)trackListener];
6964
}
7065

7166
- (BOOL)removeNotification:(NSUInteger)notificationId {
@@ -91,12 +86,18 @@ - (void)clearAllNotifications {
9186

9287
- (void)sendNotifications:(OPTLYNotificationType)type args:(NSArray *)args {
9388
OPTLYNotificationHolder *notification = _notifications[@(type)];
94-
for (id<OPTLYNotificationDelegate> object in notification.allValues) {
89+
for (GenericListener listener in notification.allValues) {
9590
@try {
96-
if (type == OPTLYNotificationTypeActivate)
97-
[self invokeSelector:object selector:@selector(onActivate:userId:attributes:variation:event:) arguments:args];
98-
else
99-
[self invokeSelector:object selector:@selector(onTrack:userId:attributes:eventTags:event:) arguments:args];
91+
switch (type) {
92+
case OPTLYNotificationTypeActivate:
93+
[self notifyActivateListener:((ActivateListener) listener) args:args];
94+
break;
95+
case OPTLYNotificationTypeTrack:
96+
[self notifyTrackListener:((TrackListener) listener) args:args];
97+
break;
98+
default:
99+
listener(args);
100+
}
100101
} @catch (NSException *exception) {
101102
NSString *logMessage = [NSString stringWithFormat:@"Problem calling notify callback. Error: %@", exception.reason];
102103
[_config.logger logMessage:logMessage withLevel:OptimizelyLogLevelError];
@@ -106,15 +107,15 @@ - (void)sendNotifications:(OPTLYNotificationType)type args:(NSArray *)args {
106107

107108
#pragma mark - Private Methods
108109

109-
- (NSInteger)addNotification:(OPTLYNotificationType)type listener:(id<OPTLYNotificationDelegate>)listener {
110+
- (NSInteger)addNotification:(OPTLYNotificationType)type listener:(GenericListener)listener {
110111
NSNumber *notificationTypeNumber = [NSNumber numberWithUnsignedInteger:type];
111112
NSNumber *notificationIdNumber = [NSNumber numberWithUnsignedInteger:_notificationId];
112113
OPTLYNotificationHolder *notificationHoldersList = _notifications[notificationTypeNumber];
113114

114115
if (![_notifications.allKeys containsObject:notificationTypeNumber] || notificationHoldersList.count == 0) {
115116
notificationHoldersList[notificationIdNumber] = listener;
116117
} else {
117-
for (id<OPTLYNotificationDelegate> notificationListener in notificationHoldersList.allValues) {
118+
for (GenericListener notificationListener in notificationHoldersList.allValues) {
118119
if (notificationListener == listener) {
119120
[_config.logger logMessage:@"The notification callback already exists." withLevel:OptimizelyLogLevelError];
120121
return -1;
@@ -126,39 +127,66 @@ - (NSInteger)addNotification:(OPTLYNotificationType)type listener:(id<OPTLYNotif
126127
return _notificationId++;
127128
}
128129

129-
- (BOOL)isNotificationTypeValid:(OPTLYNotificationType)notificationType expectedNotificationType:(OPTLYNotificationType)expectedNotificationType {
130-
if (notificationType != expectedNotificationType) {
131-
NSString *logMessage = [NSString stringWithFormat:@"Invalid notification type provided for %lu listener.", (unsigned long)expectedNotificationType];
130+
- (void)notifyActivateListener:(ActivateListener)listener args:(NSArray *)args {
131+
132+
if(args.count < 5) {
133+
NSString *logMessage = [NSString stringWithFormat:@"Not enough arguments to call %@ for notification callback.", listener];
132134
[_config.logger logMessage:logMessage withLevel:OptimizelyLogLevelError];
133-
return NO;
135+
return; // Not enough arguments in the array
134136
}
135-
return YES;
137+
138+
OPTLYExperiment *experiment = (OPTLYExperiment *)args[0];
139+
assert(experiment);
140+
assert([experiment isKindOfClass:[OPTLYExperiment class]]);
141+
142+
NSString *userId = (NSString *)args[1];
143+
assert(userId);
144+
assert([userId isKindOfClass:[NSString class]]);
145+
146+
NSDictionary *attributes = (NSDictionary *)args[2];
147+
assert(attributes);
148+
assert([attributes isKindOfClass:[NSDictionary class]]);
149+
150+
OPTLYVariation *variation = (OPTLYVariation *)args[3];
151+
assert(variation);
152+
assert([variation isKindOfClass:[OPTLYVariation class]]);
153+
154+
NSDictionary *logEvent = (NSDictionary *)args[4];
155+
assert(logEvent);
156+
assert([logEvent isKindOfClass:[NSDictionary class]]);
157+
158+
listener(experiment, userId, attributes, variation, logEvent);
136159
}
137160

138-
- (void)invokeSelector:(id)object selector:(SEL)selector arguments:(NSArray *)arguments {
139-
Method method = class_getInstanceMethod([object class], selector);
140-
int argumentCount = method_getNumberOfArguments(method);
161+
- (void)notifyTrackListener:(TrackListener)listener args:(NSArray *)args {
141162

142-
// The first two arguments are the hidden arguments self and _cmd
143-
int hiddenArguments = 2;
144-
145-
if(argumentCount > [arguments count] + hiddenArguments) {
146-
NSString *logMessage = [NSString stringWithFormat:@"Not enough arguments to call %@ for notification Delegate.", object];
163+
if(args.count < 5) {
164+
NSString *logMessage = [NSString stringWithFormat:@"Not enough arguments to call %@ for notification callback.", listener];
147165
[_config.logger logMessage:logMessage withLevel:OptimizelyLogLevelError];
148166
return; // Not enough arguments in the array
149167
}
150168

151-
NSMethodSignature *signature = [object methodSignatureForSelector:selector];
152-
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
153-
[invocation setTarget:object];
154-
[invocation setSelector:selector];
169+
NSString *eventKey = (NSString *)args[0];
170+
assert(eventKey);
171+
assert([eventKey isKindOfClass:[NSString class]]);
155172

156-
for(int i=0; i<[arguments count]; i++) {
157-
id arg = [arguments objectAtIndex:i];
158-
[invocation setArgument:&arg atIndex:i+hiddenArguments];
159-
}
173+
NSString *userId = (NSString *)args[1];
174+
assert(userId);
175+
assert([userId isKindOfClass:[NSString class]]);
176+
177+
NSDictionary *attributes = (NSDictionary *)args[2];
178+
assert(attributes);
179+
assert([attributes isKindOfClass:[NSDictionary class]]);
180+
181+
NSDictionary *eventTags = (NSDictionary *)args[3];
182+
assert(eventTags);
183+
assert([eventTags isKindOfClass:[NSDictionary class]]);
184+
185+
NSDictionary *logEvent = (NSDictionary *)args[4];
186+
assert(logEvent);
187+
assert([logEvent isKindOfClass:[NSDictionary class]]);
160188

161-
[invocation invoke]; // Invoke the selector
189+
listener(eventKey, userId, attributes, eventTags, logEvent);
162190
}
163191

164192
@end

OptimizelySDKCore/OptimizelySDKCore/OPTLYNotificationDelegate.h

Lines changed: 0 additions & 46 deletions
This file was deleted.

OptimizelySDKCore/OptimizelySDKCore/OptimizelySDKCore.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
#import "OPTLYLoggerMessages.h"
5252
#import "OPTLYNetworkService.h"
5353
#import "OPTLYNotificationCenter.h"
54-
#import "OPTLYNotificationDelegate.h"
5554
#import "OPTLYProjectConfig.h"
5655
#import "OPTLYProjectConfigBuilder.h"
5756
#import "OPTLYQueue.h"

0 commit comments

Comments
 (0)