0

edit: I finally solved this, it was a combination of a caching problem and a missing line of code. I never actually added the task to the view controller, somehow I missed that step. But also I had strange errors just running the github demo project and had to reboot and sudo delete the cache directory in order to get Xcode to function as it should.


I am trying to implement Research Kit in Objective-C. There are no tutorials and very little documentation to turn to. I am getting a crash "Visual consent step has no visible scenes". I have one view controller and on that view controller I have a button that triggers the IBAction "consentTapped". I have attempted to adapt the Ray Wenderlich tutorial http://www.raywenderlich.com/104575/researchkit-tutorial-with-swift and this GitHub project: https://github.com/weberbry/ResearchKitConsentDemo

In an attempt to troubleshoot this myself I have put all the code in viewDidAppear, taking it out of encapsulated methods because I thought I made a mistake that way but there is still a problem:

Here is my code:

#import "ViewController.h"
#import <ResearchKit/ResearchKit.h>

@interface ViewController ()<ORKTaskViewControllerDelegate>

@property (strong, nonatomic) ORKConsentDocument *consentDocument;
@property (strong, nonatomic) ORKOrderedTask *orderedTask;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];


    NSString *resource = [[NSBundle mainBundle] pathForResource:@"ConsentText" ofType:@"json"];
    NSData *consentData = [NSData dataWithContentsOfFile:resource];
    NSDictionary *parsedConsentData = [NSJSONSerialization JSONObjectWithData:consentData options:NSJSONReadingMutableContainers error:nil];

    NSArray *sectionDataParsedFromInputFile = [parsedConsentData objectForKey:@"sections"];


    NSMutableArray *consentSections = [NSMutableArray new];
    for (NSDictionary *sectionDictionary in sectionDataParsedFromInputFile) {


        ORKConsentSectionType sectionType = [[sectionDictionary objectForKey:@"sectionType"] integerValue];
        NSString *title = [sectionDictionary objectForKey:@"sectionTitle"];
        NSString *summary = [sectionDictionary objectForKey:@"sectionSummary"];
        NSString *detail = [sectionDictionary objectForKey:@"sectionDetail"];

        ORKConsentSection *section = [[ORKConsentSection alloc] initWithType:sectionType];
        section.title = title;
        section.summary = summary;
        section.htmlContent = detail;


        ORKConsentSection *consentSection = section;
        [consentSections addObject:consentSection];
    }


    ORKConsentSection *introSection = [[ORKConsentSection alloc] initWithType:ORKConsentSectionTypeOnlyInDocument];
    introSection.title = @"Intro Language";
    introSection.content = @"This will only be shown in the consent document because this sectionType is map to ORKConsentSectionTypeOnlyInDocument. A consent document can include many sections with type ORKConsentSectionTypeOnlyInDocument. In this document there is a ORKConsentSectionTypeOnlyInDocument section as an intro and one as a closing section";
    [consentSections insertObject:introSection atIndex:0];


    ORKConsentSection *closingSection = [[ORKConsentSection alloc] initWithType:ORKConsentSectionTypeOnlyInDocument];
    closingSection.title = @"Additional Terms";
    closingSection.htmlContent = @"Adding a ORKConsentSectionTypeOnlyInDocument at the end of a consent can be helpful to include any additional legal or related information.";
    [consentSections addObject:closingSection];


    self.consentDocument = [ORKConsentDocument new];
    self.consentDocument.title = @"Demo Consent";
    self.consentDocument.sections = consentSections;


    ORKConsentSignature *signature = [ORKConsentSignature new];
    self.consentDocument.signatures = [NSArray arrayWithObject:signature];


    ORKVisualConsentStep *visualConsentStep = [[ORKVisualConsentStep alloc] initWithIdentifier:@"visualConsentStep" document:self.consentDocument];


    ORKConsentReviewStep *consentReviewStep = [[ORKConsentReviewStep alloc] initWithIdentifier:@"consentReviewStep" signature:self.consentDocument.signatures.firstObject inDocument:self.consentDocument];
    consentReviewStep.text = @"Review Consent!";
    consentReviewStep.reasonForConsent = @"I confirm that I consent to join this study";

    self.orderedTask =  [[ORKOrderedTask alloc] initWithIdentifier:@"consent" steps:@[visualConsentStep, consentReviewStep]];

}

- (IBAction)consentTapped:(id)sender {

    ORKTaskViewController *taskViewController = [[ORKTaskViewController alloc]initWithTask:self.orderedTask taskRunUUID:nil];
    taskViewController.delegate = self;
    [self presentViewController:taskViewController animated:YES completion:nil];
}

- (void)taskViewController:(ORKTaskViewController *)taskViewController
       didFinishWithReason:(ORKTaskViewControllerFinishReason)reason
                     error:(NSError *)error {
    ORKTaskResult *taskResult = [taskViewController result];
    [self dismissViewControllerAnimated:YES completion:nil];
}

Due to the wording of the error I feel like there should be another view controller scene but I didn't see one on the Ray Wenderlich tutorial unless I missed it. I don't know swift at all yet so if you do and you see that I missed something please let me know.

The crash happens as you leave viewDidAppear.

Also this is my very first post here so if I have not followed community guidelines please let me know and I will modify my post at once.


edit: here is the working code. And remember, sudo delete your DerivedData folder, and reboot if you have strange errors in addition to the original error I posted. The missing line was "taskViewController.task = self.orderedTask;"

#import "ViewController.h"
#import <ResearchKit/ResearchKit.h>

@interface ViewController ()<ORKTaskViewControllerDelegate>

@property (strong, nonatomic) ORKConsentDocument *consentDocument;
@property (strong, nonatomic) ORKOrderedTask *orderedTask;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];


    NSString *resource = [[NSBundle mainBundle] pathForResource:@"ConsentText" ofType:@"json"];
    NSData *consentData = [NSData dataWithContentsOfFile:resource];
    NSDictionary *parsedConsentData = [NSJSONSerialization JSONObjectWithData:consentData options:NSJSONReadingMutableContainers error:nil];

    NSArray *sectionDataParsedFromInputFile = [parsedConsentData objectForKey:@"sections"];

    NSMutableArray *consentSections = [NSMutableArray new];
    for (NSDictionary *sectionDictionary in sectionDataParsedFromInputFile) {

        ORKConsentSectionType sectionType = [[sectionDictionary objectForKey:@"sectionType"] integerValue];
        NSString *title = [sectionDictionary objectForKey:@"sectionTitle"];
        NSString *summary = [sectionDictionary objectForKey:@"sectionSummary"];
        NSString *detail = [sectionDictionary objectForKey:@"sectionDetail"];

        ORKConsentSection *section = [[ORKConsentSection alloc] initWithType:sectionType];
        section.title = title;
        section.summary = summary;
        section.htmlContent = detail;

        ORKConsentSection *consentSection = section;
        [consentSections addObject:consentSection];
    }

    ORKConsentSection *introSection = [[ORKConsentSection alloc] initWithType:ORKConsentSectionTypeOnlyInDocument];
    introSection.title = @"Intro Language";
    introSection.htmlContent = @"This will only be shown in the consent document because this sectionType is map to ORKConsentSectionTypeOnlyInDocument. A consent document can include many sections with type ORKConsentSectionTypeOnlyInDocument. In this document there is a ORKConsentSectionTypeOnlyInDocument section as an intro and one as a closing section";

    [consentSections insertObject:introSection atIndex:0];


    ORKConsentSection *closingSection = [[ORKConsentSection alloc] initWithType:ORKConsentSectionTypeOnlyInDocument];
    closingSection.title = @"Additional Terms";
    closingSection.htmlContent = @"Adding a ORKConsentSectionTypeOnlyInDocument at the end of a consent can be helpful to include any additional legal or related information.";
    [consentSections addObject:closingSection];


    NSArray *sections = consentSections;


    self.consentDocument = [ORKConsentDocument new];
    self.consentDocument.title = @"Demo Consent";
    self.consentDocument.sections = consentSections;

    ORKConsentSignature *signature = [ORKConsentSignature new];
    self.consentDocument.signatures = [NSArray arrayWithObject:signature];


    ORKVisualConsentStep *visualConsentStep = [[ORKVisualConsentStep alloc] initWithIdentifier:@"visualConsentStep" document:self.consentDocument];


    ORKConsentReviewStep *consentReviewStep = [[ORKConsentReviewStep alloc] initWithIdentifier:@"consentReviewStep" signature:self.consentDocument.signatures.firstObject inDocument:self.consentDocument];
    consentReviewStep.text = @"Review Consent!";
    consentReviewStep.reasonForConsent = @"I confirm that I consent to join this study";


    self.orderedTask =  [[ORKOrderedTask alloc] initWithIdentifier:@"consent" steps:@[visualConsentStep, consentReviewStep]];

}

- (IBAction)consentTapped:(id)sender {

    ORKTaskViewController *taskViewController = [[ORKTaskViewController alloc] init];
    taskViewController.task = self.orderedTask;
    taskViewController.delegate = self;
    [self presentViewController:taskViewController animated:YES completion:nil];
}

- (void)taskViewController:(ORKTaskViewController *)taskViewController
       didFinishWithReason:(ORKTaskViewControllerFinishReason)reason
                     error:(NSError *)error {
    ORKTaskResult *taskResult = [taskViewController result];
    [self dismissViewControllerAnimated:YES completion:nil];
}
Abbey Jackson
  • 885
  • 10
  • 20
  • this is solved, I added the working code to the bottom – Abbey Jackson Jul 12 '15 at 20:41
  • Glad it's solved. In this case, rather than editing the question it is a better SO practice to answer your own question and then accept your answer. :-) – Ricardo Sanchez-Saez Jul 13 '15 at 11:03
  • Ok thanks for telling me! – Abbey Jackson Jul 14 '15 at 15:35
  • If you want, you can still post the solution as your own answer to this question, then edit the question to remove the solution from there, and finally accept your own question later. That helps because it makes this questions as *answered* on the question list (so it stops attracting "question answerers", and attracts "question readers" instead). ;-) – Ricardo Sanchez-Saez Jul 14 '15 at 17:10

1 Answers1

0

Answer by Abbey Jackson:

Here is the working code. And remember, sudo delete your DerivedData folder, and reboot if you have strange errors in addition to the original error I posted. The missing line was taskViewController.task = self.orderedTask;

#import "ViewController.h"
#import <ResearchKit/ResearchKit.h>

@interface ViewController ()<ORKTaskViewControllerDelegate>

@property (strong, nonatomic) ORKConsentDocument *consentDocument;
@property (strong, nonatomic) ORKOrderedTask *orderedTask;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];


    NSString *resource = [[NSBundle mainBundle] pathForResource:@"ConsentText" ofType:@"json"];
    NSData *consentData = [NSData dataWithContentsOfFile:resource];
    NSDictionary *parsedConsentData = [NSJSONSerialization JSONObjectWithData:consentData options:NSJSONReadingMutableContainers error:nil];

    NSArray *sectionDataParsedFromInputFile = [parsedConsentData objectForKey:@"sections"];

    NSMutableArray *consentSections = [NSMutableArray new];
    for (NSDictionary *sectionDictionary in sectionDataParsedFromInputFile) {

        ORKConsentSectionType sectionType = [[sectionDictionary objectForKey:@"sectionType"] integerValue];
        NSString *title = [sectionDictionary objectForKey:@"sectionTitle"];
        NSString *summary = [sectionDictionary objectForKey:@"sectionSummary"];
        NSString *detail = [sectionDictionary objectForKey:@"sectionDetail"];

        ORKConsentSection *section = [[ORKConsentSection alloc] initWithType:sectionType];
        section.title = title;
        section.summary = summary;
        section.htmlContent = detail;

        ORKConsentSection *consentSection = section;
        [consentSections addObject:consentSection];
    }

    ORKConsentSection *introSection = [[ORKConsentSection alloc] initWithType:ORKConsentSectionTypeOnlyInDocument];
    introSection.title = @"Intro Language";
    introSection.htmlContent = @"This will only be shown in the consent document because this sectionType is map to ORKConsentSectionTypeOnlyInDocument. A consent document can include many sections with type ORKConsentSectionTypeOnlyInDocument. In this document there is a ORKConsentSectionTypeOnlyInDocument section as an intro and one as a closing section";

    [consentSections insertObject:introSection atIndex:0];


    ORKConsentSection *closingSection = [[ORKConsentSection alloc] initWithType:ORKConsentSectionTypeOnlyInDocument];
    closingSection.title = @"Additional Terms";
    closingSection.htmlContent = @"Adding a ORKConsentSectionTypeOnlyInDocument at the end of a consent can be helpful to include any additional legal or related information.";
    [consentSections addObject:closingSection];

    NSArray *sections = consentSections;

    self.consentDocument = [ORKConsentDocument new];
    self.consentDocument.title = @"Demo Consent";
    self.consentDocument.sections = consentSections;

    ORKConsentSignature *signature = [ORKConsentSignature new];
    self.consentDocument.signatures = [NSArray arrayWithObject:signature];

    ORKVisualConsentStep *visualConsentStep = [[ORKVisualConsentStep alloc] initWithIdentifier:@"visualConsentStep" document:self.consentDocument];

    ORKConsentReviewStep *consentReviewStep = [[ORKConsentReviewStep alloc] initWithIdentifier:@"consentReviewStep" signature:self.consentDocument.signatures.firstObject inDocument:self.consentDocument];
    consentReviewStep.text = @"Review Consent!";
    consentReviewStep.reasonForConsent = @"I confirm that I consent to join this study";

    self.orderedTask =  [[ORKOrderedTask alloc] initWithIdentifier:@"consent" steps:@[visualConsentStep, consentReviewStep]];
}

- (IBAction)consentTapped:(id)sender {

    ORKTaskViewController *taskViewController = [[ORKTaskViewController alloc] init];
    taskViewController.task = self.orderedTask;
    taskViewController.delegate = self;
    [self presentViewController:taskViewController animated:YES completion:nil];
}

- (void)taskViewController:(ORKTaskViewController *)taskViewController
       didFinishWithReason:(ORKTaskViewControllerFinishReason)reason
                     error:(NSError *)error {
    ORKTaskResult *taskResult = [taskViewController result];
    [self dismissViewControllerAnimated:YES completion:nil];
}
Ricardo Sanchez-Saez
  • 9,466
  • 8
  • 53
  • 92