1

My product owner wants us to report more information on the state of the product when a user contacts customer service through an in-app form. The form eventually results in an email being sent to a customer service email list and handled elsewhere.

The part I'm struggling with is how to augment my existing iOS project to allow for some controller to collect diagnostic information from a variety of disparate classes, and do it in a way that's minimally invasive and won't cause a headache if refactoring later.

Blocks

I've experimented with a few ideas, including having an interface that allows an arbitrary class to register a block to be executed when attempting to collect the diagnostic information:

[DiagnosticCollectionController addBlockForDiagnosis:^(DiagnosticCollectionController *controller){
    // Add some information here to the controller to send in the diagnostic report
}];

Notifications

Another idea I had in mind was to have the diagnostic controller broadcast a notification when it's ready to start gathering information, so that other objects can attach what they need to. The (potential) advantage here is that I can get away from using blocks thus prevent myself from having block copy issues:

[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(someSelectorToHandleDiagnosticPopulation:) 
                                             name:DiagnosticCollectionControllerWillSendDiagnostics 
                                           object:someDiagnosticController];
// Elsewhere
- (void) someSelectorToHandleDiagnosticPopulation:(NSNotification *)note {
    DiagnosticController *controller = [note object];
    [controller addDiagnosticData:someDataDictionary];
}
1

I like your notification approach better than your block approach. I recommend having each pertinent subsystem or component implement an interface that can return status information when requested. They would then register themselves with a centralized status collection service. At key times, the status service could fetch status from each registered component, build a report, and attach it to the customer service email. Whether the fetching is done manually or through the iOS notification system is less important, I think.

BTW, if the objects that can provide status are transient, then you might need to be careful that the status collection service not hold references to them when they are no longer needed. A weak reference might help here.

  • This is an excellent suggestion, and extremely close to what I finally settled on. – Hyperbole Jul 31 '14 at 13:29
0

Finally, I went with a setup close to what Randall suggested, after some more thinking and some distraction.

The interfaces that handle coordinating the diagnostic work look like this:

@interface DiagnosticController
+ (void) addDiagnosticProvider:(id<DiagnosticProvider>)provider;
+ (void) removeDiagnosticProvider:(id<DiagnosticProvider>)provider;
@end

@protocol DiagnosticProvider <NSObject>
- (NSDictionary *) diagnosticData;
@end

The DiagnosticController itself keeps a list of __unsafe_unretained pointers so objects can remove themselves from the list of providers when they dealloc. I went with __unsafe_unretained to make this backward compatible with earlier versions of iOS instead of, say, NSHashTable with the NSHashTableWeakMemory option. If I have some time in the future, I might cluster the DiagnosticController to allow for multiple backing stores depending on the runtime.

  • "Finally, I went with a setup close to what Randall suggested" you could have upvoted him – Saran Jun 15 '16 at 2:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.