How to effectively save user settings in a Cocos2d game - ios

So I currently have a functioning way of saving settings for my Cocos2d game, and the method I am using is an XML parser.
First of all, is it better to use NSUserDefaults for something like this?
EDIT: I DO APPOLOGIZE FOR THE LONG POST, IF YOU ALREADY KNOW HOW AN XML PARSER WORKS JUST SKIP TO THE END.
Here is my GlobalSettings.h:
#import <Foundation/Foundation.h>
#interface GlobalSettings : NSObject {
// Declare variables with an underscore in front, for example:
int _currency;
BOOL _BankerBossDefeated;
BOOL _BabyBossDefeated;
BOOL _DuckBossDefeated;
BOOL _BaseBallBossDefeated;
BOOL _NewtonBossDefeated;
BOOL _CatchExtender;
BOOL _CatchExtenderEnabled;
BOOL _SpeedBoost;
BOOL _SpeedBoostEnabled;
}
// Declare your variable properties without an underscore, for example:
#property (nonatomic, assign) int currency;
#property (nonatomic, assign) BOOL BankerBossDefeated;
#property (nonatomic, assign) BOOL BabyBossDefeated;
#property (nonatomic, assign) BOOL DuckBossDefeated;
#property (nonatomic, assign) BOOL BaseBallBossDefeated;
#property (nonatomic, assign) BOOL NewtonBossDefeated;
#property (nonatomic, assign) BOOL SpeedBoost;
#property (nonatomic, assign) BOOL CatchExtender;
#property (nonatomic, assign) BOOL SpeedBoostEnabled;
#property (nonatomic, assign) BOOL CatchExtenderEnabled;
// Put your custom init method interface here:
-(id)initWithcurrency:(int)currency
BankerBossDefeated:(BOOL)BankerBossDefeated
BabyBossDefeated:(BOOL)BabyBossDefeated
DuckBossDefeated:(BOOL)DuckBossDefeated
BaseBallBossDefeated:(BOOL)BaseBallBossDefeated
NewtonBossDefeated:(BOOL)NewtonBossDefeated
CatchExtender:(BOOL)CatchExtender
SpeedBoost:(BOOL)SpeedBoost
CatchExtenderEnabled:(BOOL)CatchExtenderEnabled
SpeedBoostEnabled:(BOOL)SpeedBoostEnabled;
#end
My GlobalSettings.m is:
#import "GlobalSettings.h"
#implementation GlobalSettings
// Synthesize your variables here, for example:
#synthesize currency = _currency;
#synthesize BankerBossDefeated = _BankerBossDefeated;
#synthesize BabyBossDefeated = _BabyBossDefeated;
#synthesize DuckBossDefeated = _DuckBossDefeated;
#synthesize BaseBallBossDefeated = _BaseBallBossDefeated;
#synthesize NewtonBossDefeated = _NewtonBossDefeated;
#synthesize SpeedBoost = _SpeedBoost;
#synthesize CatchExtender = _CatchExtender;
#synthesize SpeedBoostEnabled = _SpeedBoostEnabled;
#synthesize CatchExtenderEnabled = _CatchExtenderEnabled;
// put your custom init method here which takes a variable
// for each class instance variable
-(id)initWithcurrency:(int)currency
BankerBossDefeated:(BOOL)BankerBossDefeated
BabyBossDefeated:(BOOL)BabyBossDefeated
DuckBossDefeated:(BOOL)DuckBossDefeated
BaseBallBossDefeated:(BOOL)BaseBallBossDefeated
NewtonBossDefeated:(BOOL)NewtonBossDefeated
CatchExtender:(BOOL)CatchExtender
SpeedBoost:(BOOL)SpeedBoost
CatchExtenderEnabled:(BOOL)CatchExtenderEnabled
SpeedBoostEnabled:(BOOL)SpeedBoostEnabled;{
if ((self = [super init])) {
// Set class instance variables based on values
// given to this method
self.currency = currency;
self.BankerBossDefeated = BankerBossDefeated;
self.BabyBossDefeated = BabyBossDefeated;
self.DuckBossDefeated = DuckBossDefeated;
self.BaseBallBossDefeated = BaseBallBossDefeated;
self.NewtonBossDefeated = NewtonBossDefeated;
self.CatchExtender = CatchExtender;
self.SpeedBoost = SpeedBoost;
self.CatchExtenderEnabled = CatchExtenderEnabled;
self.SpeedBoostEnabled = SpeedBoostEnabled;
}
return self;
}
- (void) dealloc {
[super dealloc];
}
#end
I then parse the XML with SettingsParser.h:
#import <Foundation/Foundation.h>
#class GlobalSettings;
#interface SettingsParser : NSObject {}
+ (GlobalSettings *)loadData;
+ (void)saveData:(GlobalSettings *)saveData;
#end
and SettingsParser.m:
#import "SettingsParser.h"
#import "GlobalSettings.h"
#import "GDataXMLNode.h"
#implementation SettingsParser
+ (NSString *)dataFilePath:(BOOL)forSave {
NSString *xmlFileName = #"GlobalSettings";
/***************************************************************************
This method is used to set up the specified xml for reading/writing.
Specify the name of the XML file you want to work with above.
You don't have to worry about the rest of the code in this method.
***************************************************************************/
NSString *xmlFileNameWithExtension = [NSString stringWithFormat:#"%#.xml",xmlFileName];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *documentsPath = [documentsDirectory stringByAppendingPathComponent:xmlFileNameWithExtension];
if (forSave || [[NSFileManager defaultManager] fileExistsAtPath:documentsPath]) {
return documentsPath;
NSLog(#"%# opened for read/write",documentsPath);
} else {
NSLog(#"Created/copied in default %#",xmlFileNameWithExtension);
return [[NSBundle mainBundle] pathForResource:xmlFileName ofType:#"xml"];
}
}
+ (GlobalSettings *)loadData {
/***************************************************************************
This loadData method is used to load data from the xml file
specified in the dataFilePath method above.
MODIFY the list of variables below which will be used to create
and return an instance of TemplateData at the end of this method.
***************************************************************************/
int currency;
BOOL BankerBossDefeated;
BOOL BabyBossDefeated;
BOOL DuckBossDefeated;
BOOL BaseBallBossDefeated;
BOOL NewtonBossDefeated;
BOOL CatchExtender;
BOOL SpeedBoost;
BOOL CatchExtenderEnabled;
BOOL SpeedBoostEnabled;
// Create NSData instance from xml in filePath
NSString *filePath = [self dataFilePath:FALSE];
NSData *xmlData = [[NSMutableData alloc] initWithContentsOfFile:filePath];
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData options:0 error:&error];
if (doc == nil) { return nil; NSLog(#"xml file is empty!");}
NSLog(#"Loading %#", filePath);
/***************************************************************************
This next line will usually have the most customisation applied because
it will be a direct reflection of what you want out of the XML file.
***************************************************************************/
NSArray *dataArray = [doc nodesForXPath:#"//GlobalSettings" error:nil];
NSLog(#"Array Contents = %#", dataArray);
/***************************************************************************
We use dataArray to populate variables created at the start of this
method. For each variable you will need to:
1. Create an array based on the elements in the xml
2. Assign the variable a value based on data in elements in the xml
***************************************************************************/
for (GDataXMLElement *element in dataArray) {
NSArray *currencyArray = [element elementsForName:#"currency"];
NSArray *BankerBossDefeatedArray = [element elementsForName:#"BankerBossDefeated"];
NSArray *BabyBossDefeatedArray = [element elementsForName:#"BabyBossDefeated"];
NSArray *DuckBossDefeatedArray = [element elementsForName:#"DuckBossDefeated"];
NSArray *BaseBallBossDefeatedArray = [element elementsForName:#"BaseBallBossDefeated"];
NSArray *NewtonBossDefeatedArray = [element elementsForName:#"NewtonBossDefeated"];
NSArray *CatchExtenderArray = [element elementsForName:#"CatchExtender"];
NSArray *SpeedBoostArray = [element elementsForName:#"SpeedBoost"];
NSArray *CatchExtenderEnabledArray = [element elementsForName:#"CatchExtenderEnabled"];
NSArray *SpeedBoostEnabledArray = [element elementsForName:#"SpeedBoostEnabled"];
// currency
if (currencyArray.count > 0) {
GDataXMLElement *currencyElement = (GDataXMLElement *) [currencyArray objectAtIndex:0];
currency = [[currencyElement stringValue] intValue];
}
// BankerBossDefeated
if (BankerBossDefeatedArray.count > 0) {
GDataXMLElement *BankerBossDefeatedElement = (GDataXMLElement *) [BankerBossDefeatedArray objectAtIndex:0];
BankerBossDefeated = [[BankerBossDefeatedElement stringValue] boolValue];
}
// DuckBossDefeated
if (DuckBossDefeatedArray.count > 0) {
GDataXMLElement *DuckBossDefeatedElement = (GDataXMLElement *) [DuckBossDefeatedArray objectAtIndex:0];
DuckBossDefeated = [[DuckBossDefeatedElement stringValue] boolValue];
}
// BabyBossDefeated
if (BabyBossDefeatedArray.count > 0) {
GDataXMLElement *BabyBossDefeatedElement = (GDataXMLElement *) [BabyBossDefeatedArray objectAtIndex:0];
BabyBossDefeated = [[BabyBossDefeatedElement stringValue] boolValue];
}
// BaseBallBossDefeated
if (BaseBallBossDefeatedArray.count > 0) {
GDataXMLElement *BaseBallBossDefeatedElement = (GDataXMLElement *) [BaseBallBossDefeatedArray objectAtIndex:0];
BaseBallBossDefeated = [[BaseBallBossDefeatedElement stringValue] boolValue];
}
// NewtonBossDefeated
if (NewtonBossDefeatedArray.count > 0) {
GDataXMLElement *NewtonBossDefeatedElement = (GDataXMLElement *) [NewtonBossDefeatedArray objectAtIndex:0];
NewtonBossDefeated = [[NewtonBossDefeatedElement stringValue] boolValue];
}
// CatchExtender
if (CatchExtenderArray.count > 0) {
GDataXMLElement *CatchExtenderElement = (GDataXMLElement *) [CatchExtenderArray objectAtIndex:0];
CatchExtender = [[CatchExtenderElement stringValue] boolValue];
}
// SpeedBoost
if (SpeedBoostArray.count > 0) {
GDataXMLElement *SpeedBoostElement = (GDataXMLElement *) [SpeedBoostArray objectAtIndex:0];
SpeedBoost = [[SpeedBoostElement stringValue] boolValue];
}
// CatchExtenderEnabled
if (CatchExtenderEnabledArray.count > 0) {
GDataXMLElement *CatchExtenderEnabledElement = (GDataXMLElement *) [CatchExtenderEnabledArray objectAtIndex:0];
CatchExtenderEnabled = [[CatchExtenderEnabledElement stringValue] boolValue];
}
// SpeedBoost
if (SpeedBoostEnabledArray.count > 0) {
GDataXMLElement *SpeedBoostEnabledElement = (GDataXMLElement *) [SpeedBoostEnabledArray objectAtIndex:0];
SpeedBoostEnabled = [[SpeedBoostEnabledElement stringValue] boolValue];
}
}
/***************************************************************************
Now the variables are populated from xml data we create an instance of
TemplateData to pass back to whatever called this method.
The initWithExampleInt:exampleBool:exampleString will need to be replaced
with whatever method you have updaed in the TemplateData class.
***************************************************************************/
//NSLog(#"XML value read for exampleInt = %i", exampleInt);
//NSLog(#"XML value read for exampleBool = %i", exampleBool);
//NSLog(#"XML value read for exampleString = %#", exampleString);
GlobalSettings *Data = [[GlobalSettings alloc] initWithcurrency:currency
BankerBossDefeated:BankerBossDefeated
BabyBossDefeated:BabyBossDefeated DuckBossDefeated:DuckBossDefeated BaseBallBossDefeated:BaseBallBossDefeated NewtonBossDefeated:NewtonBossDefeated
CatchExtender:CatchExtender
SpeedBoost:SpeedBoost CatchExtenderEnabled:CatchExtenderEnabled
SpeedBoostEnabled:SpeedBoostEnabled];
[doc release];
[xmlData release];
return Data;
[Data release];
}
+ (void)saveData:(GlobalSettings *)saveData {
/***************************************************************************
This method writes data to the xml based on a TemplateData instance
You will have to be very aware of the intended xml contents and structure
as you will be wiping and re-writing the whole xml file.
We write an xml by creating elements and adding 'children' to them.
You'll need to write a line for each element to build the hierarchy // <-- MODIFY CODE ACCORDINGLY
***************************************************************************/
GDataXMLElement *GlobalSettingsElement = [GDataXMLNode elementWithName:#"GlobalSettings"];
GDataXMLElement *currencyElement = [GDataXMLNode elementWithName:#"currency"
stringValue:[[NSNumber numberWithInt:saveData.currency] stringValue]];
GDataXMLElement *BankerBossDefeatedElement = [GDataXMLNode elementWithName:#"BankerBossDefeated"
stringValue:[[NSNumber numberWithBool:saveData.BankerBossDefeated] stringValue]];
GDataXMLElement *BabyBossDefeatedElement = [GDataXMLNode elementWithName:#"BabyBossDefeated"
stringValue:[[NSNumber numberWithBool:saveData.BabyBossDefeated] stringValue]];
GDataXMLElement *DuckBossDefeatedElement = [GDataXMLNode elementWithName:#"DuckBossDefeated"
stringValue:[[NSNumber numberWithBool:saveData.DuckBossDefeated] stringValue]];
GDataXMLElement *BaseBallBossDefeatedElement = [GDataXMLNode elementWithName:#"BaseBallBossDefeated"
stringValue:[[NSNumber numberWithBool:saveData.BaseBallBossDefeated] stringValue]];
GDataXMLElement *NewtonBossDefeatedElement = [GDataXMLNode elementWithName:#"NewtonBossDefeated"
stringValue:[[NSNumber numberWithBool:saveData.NewtonBossDefeated] stringValue]];
GDataXMLElement *CatchExtenderElement = [GDataXMLNode elementWithName:#"CatchExtender"
stringValue:[[NSNumber numberWithBool:saveData.CatchExtender] stringValue]];
GDataXMLElement *SpeedBoostElement = [GDataXMLNode elementWithName:#"SpeedBoost"
stringValue:[[NSNumber numberWithBool:saveData.SpeedBoost] stringValue]];
GDataXMLElement *CatchExtenderEnabledElement = [GDataXMLNode elementWithName:#"CatchExtenderEnabled"
stringValue:[[NSNumber numberWithBool:saveData.CatchExtender] stringValue]];
GDataXMLElement *SpeedBoostEnabledElement = [GDataXMLNode elementWithName:#"SpeedBoostEnabled"
stringValue:[[NSNumber numberWithBool:saveData.SpeedBoost] stringValue]];
// Using the elements just created, set up the hierarchy
[GlobalSettingsElement addChild:currencyElement];
[GlobalSettingsElement addChild:BankerBossDefeatedElement];
[GlobalSettingsElement addChild:BabyBossDefeatedElement];
[GlobalSettingsElement addChild:DuckBossDefeatedElement];
[GlobalSettingsElement addChild:BaseBallBossDefeatedElement];
[GlobalSettingsElement addChild:NewtonBossDefeatedElement];
[GlobalSettingsElement addChild:CatchExtenderElement];
[GlobalSettingsElement addChild:SpeedBoostElement];
[GlobalSettingsElement addChild:CatchExtenderEnabledElement];
[GlobalSettingsElement addChild:SpeedBoostEnabledElement];
GDataXMLDocument *document = [[[GDataXMLDocument alloc]
initWithRootElement:GlobalSettingsElement] autorelease];
NSData *xmlData = document.XMLData;
NSString *filePath = [self dataFilePath:TRUE];
NSLog(#"Saving data to %#...", filePath);
[xmlData writeToFile:filePath atomically:YES];
}
#end
EDIT: THE ACTUAL PROBLEM BEGINS HERE:
In my menu class I have two switches that come up when CatchExtender and SpeedBoost become enabled (they are purchased in the game's store). In those switches, I want to set SpeedBoostEnabled and CatchExtenderEnabled depending on the switch.
These are the switches:
IN MY INIT:
if (GlobalSettings.CatchExtender == TRUE) {
if(GlobalSettings.SpeedBoost == TRUE){
catchSwitch = [[ UISwitch alloc ] initWithFrame: CGRectMake(220, 400, 10, 10)];
catchSwitch.center = CGPointMake(240, 450);
CCLabelTTF *catchLabel = [CCLabelTTF labelWithString:#"Catch Extender" fontName:#"Chalkduster" fontSize:15];
catchLabel.color = ccWHITE;
catchLabel.position = CGPointMake(240, 60);
[self addChild: catchLabel];
}else{
catchSwitch = [[ UISwitch alloc ] initWithFrame: CGRectMake(160, 400, 10, 10)];
catchSwitch.center = CGPointMake(160, 450);
CCLabelTTF *catchLabel = [CCLabelTTF labelWithString:#"Catch Extender" fontName:#"Chalkduster" fontSize:15];
catchLabel.color = ccWHITE;
catchLabel.position = CGPointMake(160, 60);
[self addChild: catchLabel];
}
catchSwitch.on = NO; //set to be OFF at start
catchSwitch.tag = 1; // this is not necessary - only to find later
[catchSwitch addTarget:self action:#selector(catchAction:) forControlEvents:UIControlEventValueChanged];
[[[CCDirector sharedDirector] openGLView] addSubview:catchSwitch];
}
if (GlobalSettings.SpeedBoost == TRUE) {
if(GlobalSettings.CatchExtender == TRUE){
speedSwitch = [[ UISwitch alloc ] initWithFrame: CGRectMake(100, 400, 10, 10)];
speedSwitch.center = CGPointMake(80, 450);
CCLabelTTF *speedLabel = [CCLabelTTF labelWithString:#"Speed Enhancer" fontName:#"Chalkduster" fontSize:15];
speedLabel.color = ccWHITE;
speedLabel.position = CGPointMake(80, 60);
[self addChild: speedLabel];
}else{
speedSwitch = [[ UISwitch alloc ] initWithFrame: CGRectMake(160, 400, 10, 10)];
speedSwitch.center = CGPointMake(160, 450);
}
speedSwitch.on = NO; //set to be OFF at start
speedSwitch.tag = 1; // this is not necessary - only to find later
[speedSwitch addTarget:self action:#selector(speedAction:) forControlEvents:UIControlEventValueChanged];
[[[CCDirector sharedDirector] openGLView] addSubview:speedSwitch];
}
IN THE ACTIONS:
- (void)catchAction:(id)sender
{
// Your logic when the switch it used
// NSLog(#"switchAction: value = %d", [sender isOn]);
if ([sender isOn]) {
GlobalSettings *GlobalSettings = [SettingsParser loadData];
GlobalSettings.CatchExtenderEnabled = TRUE;
UIAlertView* dialog = [[UIAlertView alloc] init];
[dialog setDelegate:self];
[dialog setTitle:#"ON"];
[dialog setMessage:#"Catch Extender is on"];
[dialog addButtonWithTitle:#"Sweet!"];
[dialog show];
[dialog release];
[SettingsParser saveData:GlobalSettings];
}else{
GlobalSettings *GlobalSettings = [SettingsParser loadData];
GlobalSettings.CatchExtenderEnabled = FALSE;
UIAlertView* dialog = [[UIAlertView alloc] init];
[dialog setDelegate:self];
[dialog setTitle:#"OFF"];
[dialog setMessage:#"Catch Extender is off"];
[dialog addButtonWithTitle:#"Thanks"];
[dialog show];
[dialog release];
[SettingsParser saveData:GlobalSettings];
}
}
- (void)speedAction:(id)sender
{
// Your logic when the switch it used
// NSLog(#"switchAction: value = %d", [sender isOn]);
if ([sender isOn]) {
GlobalSettings *GlobalSettings = [SettingsParser loadData];
GlobalSettings.SpeedBoostEnabled = TRUE;
UIAlertView* dialog = [[UIAlertView alloc] init];
[dialog setDelegate:self];
[dialog setTitle:#"ON"];
[dialog setMessage:#"Speed Enhancer is on"];
[dialog addButtonWithTitle:#"Sweet!"];
[dialog show];
[dialog release];
[SettingsParser saveData:GlobalSettings];
}else{
GlobalSettings *GlobalSettings = [SettingsParser loadData];
GlobalSettings.SpeedBoostEnabled = FALSE;
UIAlertView* dialog = [[UIAlertView alloc] init];
[dialog setDelegate:self];
[dialog setTitle:#"OFF"];
[dialog setMessage:#"Speed Enhancer is off"];
[dialog addButtonWithTitle:#"Thanks"];
[dialog show];
[dialog release];
[SettingsParser saveData:GlobalSettings];
}
}
In the classes that hold the data for the game levels, I check these Booleans normally with a simple if statement. But it doesn't seem to work, the settings don't seem to save because in the Log it doesn't seem like the values have changed in the XML file..
Again sorry for the long post but this issue is kinda bugging me.

I've never used Cocos2D before but this seems like exactly what you would use NSUserDefaults for in a typical iOS app, like this: [[NSUserDefaults standardUserDefaults] setBool:YES ForKey:#"Key"];

Related

Research Kit - Objective-C error: "Visual consent step has no visible scenes"

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];
}
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];
}

Call out of an Array, objectAtIndex

I have an Array with 10 Objects. I take the first Object and put it into my Label with a String.
Then I want to have a Method that increases the objectAtIndex by 1.
This is my Code :
//.m
#interface GameViewController () {
NSInteger _labelIndex;
}
#property (nonatomic) NSArray *playerArray;
#property (nonatomic) NSString *playerLabel;
- (void)viewDidLoad {
[super viewDidLoad];
self.playerArray = [NSArray arrayWithObjects:#"FIRST", #"SECOND", #"THIRD", #"FOURTH", #"FIFTH", #"SIXT", #"SEVENTH", #"EIGTH", #"NINTH", #"TENTH", nil];
_labelIndex = 0;
[self updateTurnLabel];
self.turnLabel.text = [NSString stringWithFormat:#"YOUR %# DRAW?", self.playerLabel];
}
Here I call the Method i another Method:
-(void) flipDraws {
self.boardView.userInteractionEnabled = NO;
[self updateTurnLabel];
CardView *cv1 = (CardView *) self.turnedDrawViews[0];
CardView *cv2 = (CardView *) self.turnedDrawViews[1];
}
This is my Method:
-(void) updateTurnLabel {
self.playerLabel = [self.playerArray objectAtIndex:_labelIndex % self.playerArray.count]; _labelIndex++;
}
I tried it with a for Loop but nothing happened. I tried it with just set the objectAtIndex:1 but my Method was not called.
What I am doing wrong?
{
int a;
}
- (void)viewDidLoad {
[super viewDidLoad];
a = 0;
self.playerArray = [NSArray arrayWithObjects:#"FIRST", #"SECOND", #"THIRD", #"FOURTH", #"FIFTH", #"SIXT", #"SEVENTH", #"EIGTH", #"NINTH", #"TENTH", nil];
self.playerLabel = [self.playerArray objectAtIndex:a];
self.turnLabel.text = [NSString stringWithFormat:#"YOUR %# DRAW?", self.playerLabel];
}
-(void) updateTurnLabel {
a +=1;
if (!a<[playerArray count])
{
a = 0;
}
self.playerLabel = [self.playerArray objectAtIndex:a];
}
call self.turnLabel.text = [NSString stringWithFormat:#"YOUR %# DRAW?", self.playerLabel]; after [self updateTurnLabel];
What are you adding +1 to in the method objectAtIndex:.
You should be maintaining a variable which tracks the current index being used, then in your method use this :
-(void) updateTurnLabel {
self.playerLabel = [self.playerArray objectAtIndex:currentIndex+1];
}

Save UICollectionViewCell progress state

I've already asked the same question about saving pressed button state and I thought that I should do in the same way to save progress state on cells but my tries are unsuccessful.
What I'm doing now: I select some UICollectionViewCell's and then press "download" button and then downolad action starts. Every cell I selected shows UIProgressView and everything is ok untill I scroll my UICollectionView up or down. When I do it another cells have progress view too but they mustn't! I know that I must save indexPath of selected cells in NSMutableArray and then in cellForItemAtIndexPath check if current cell indexPath is in my array and then show or hide my cell's subviews. I do that but it only works with cell selection! What should I do to save progress view state on each cell this progress really there?
Here is my code:
In cellForItemAtIndexPath:
NSNumber *rowNsNum = [NSNumber numberWithUnsignedInt:(unsigned int)indexPath.row];
if ([selecedCellsArray containsObject:[NSString stringWithFormat:#"%#",rowNsNum]] )
{
cell.selectedBG.hidden = NO;
cell.selectedImg.hidden = NO;
}
else
{
cell.selectedBG.hidden = YES;
cell.selectedImg.hidden = YES;
cell.progressView.hidden = YES;
}
In didSelectItemAtIndexPath:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
...
// Add the selected item into the array
[selectedIds addObject:selectedId];
[selectedVideos addObject:selectedVideo];
AVMVideoCell *collectionCell = (AVMVideoCell*)[collectionView cellForItemAtIndexPath:indexPath];
NSNumber *rowNsNum = [NSNumber numberWithUnsignedInt:(unsigned int)indexPath.row];
if ( ![selecedCellsArray containsObject:[NSString stringWithFormat:#"%#",rowNsNum]] )
{
[selecedCellsArray addObject:[NSString stringWithFormat:#"%ld",(long)indexPath.row]];
collectionCell.selectedBG.hidden = NO;
collectionCell.selectedImg.hidden = NO;
[collectionCell setSelected:YES];
}
}
}
In didDeselectItemAtIndexPath:
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {
...
// Delete the selected item from the array
[selectedIds removeObject:selectedId];
[selectedVideos removeObject:selectedVideo];
AVMVideoCell *collectionCell = (AVMVideoCell*)[collectionView cellForItemAtIndexPath:indexPath];
NSNumber *rowNsNum = [NSNumber numberWithUnsignedInt:(unsigned int)indexPath.row];
if ( [selecedCellsArray containsObject:[NSString stringWithFormat:#"%#",rowNsNum]] )
{
[selecedCellsArray removeObject:[NSString stringWithFormat:#"%ld",(long)indexPath.row]];
collectionCell.selectedBG.hidden = YES;
collectionCell.selectedImg.hidden = YES;
[collectionCell setSelected:NO];
}
}
And this is how I show my progress:
-(NSString *)progress:(long long )val1 : (long long )val2 : (AVMVideoCell *)cell : (NSString *)name : (NSIndexPath *)path{
float progress = ((float)val1) / val2;
NSString *prog = [[NSNumber numberWithFloat:progress*100] stringValue];
if (prog != nil){
if(cell.isSelected){
cell.selectedImg.hidden = YES;
cell.progressView.hidden = NO;
}
}
NSNumber *rowNsNum = [NSNumber numberWithUnsignedInt:(unsigned int)path.row];
if ( [selecedCellsArray containsObject:[NSString stringWithFormat:#"%#",rowNsNum]])
{
[cell.progressView setProgress:progress animated:YES];
}
if([prog intValue]==100){
cell.progressView.hidden = YES;
}
return prog;
}
EDIT: AVMVideoCell.m
#import "AVMVideoCell.h"
#implementation AVMVideoCell
{
NSString *fullUrl;
}
#synthesize imageView;
#synthesize selectedBG;
#synthesize progressLabel;
#synthesize progressView;
#synthesize selectedImg;
#synthesize progLayer;
-(void) setVideo:(AVMDataStore *)video {
if(_video != video) {
_video = video;
}
NSString *durString = [NSString stringWithFormat:#"%#",[self timeFormatted:_video.duration]];
if((_video.filePreview != nil) && ![_video.filePreview isEqualToString:#""]){
fullUrl = [NSString stringWithFormat:#"http://example.com%#",_video.filePreview];
}
NSURL *imgURL = [NSURL URLWithString:fullUrl];
[self.imageView setImageWithURL:imgURL
placeholderImage:[UIImage imageNamed:#"yesterday.png"] options:0 usingActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
self.duration.text = durString;
}
- (NSString *)timeFormatted:(int)totalSeconds
{
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
int hours = totalSeconds / 3600;
return [NSString stringWithFormat:#"%02d:%02d:%02d",hours, minutes, seconds];
}
#end
EDIT 2: Explanation about progress
My progressView is not an IBOutlet it's a #property (nonatomic,strong) UIProgressView *progressView; (AVMVideoCell.h)
I allocate and initialize it in cellForItemAtIndexPath:
cell.progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0,0, 150.0f, 1.0f)];
cell.progressView.trackTintColor = [UIColor colorWithWhite:255 alpha:0.5f];
cell.progressView.progressTintColor = [UIColor whiteColor];
[cell.progLayer addSubview:cell.progressView];
cell.progressView.hidden = YES;
cell.progressView.tag = indexPath.row+500;
This is where I call progress change showing:
-(void)downloadStart:(NSString*)fileUrl : (NSString*)name : (AVMVideoCell *) cell : (NSIndexPath *)path{
NSURL *URL = [NSURL URLWithString:fileUrl];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSString *fileName = [NSString stringWithFormat:#"%#.mp4",name]; //set full file name to save
AFHTTPRequestOperation *downloadRequest = [[AFHTTPRequestOperation alloc] initWithRequest:request]; //create download request
[downloadRequest setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSData *data = [[NSData alloc] initWithData:responseObject];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *pathToFile = [NSString stringWithFormat:#"%#/%#", [paths firstObject],fileName]; // path to 'Documents'
NSString *pathOfFile = [[paths objectAtIndex:0] stringByAppendingPathComponent:fileName];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:pathOfFile append:NO];
BOOL success = [data writeToFile:pathToFile atomically:YES];
if(success){
[self checkIfExists:name : cell :path];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"file downloading error : %#", [error localizedDescription]);
UIAlertView * alert=[[UIAlertView alloc]initWithTitle:#"Error" message:[NSString stringWithFormat:#"%#",error] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil ];
[alert show];
cell.progressView.hidden = YES;
}];
// Step 5: begin asynchronous download
[downloadRequest start];
[downloadRequest setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
[self progress:totalBytesRead :totalBytesExpectedToRead :cell :name : path]; //here I pass val1 and val 2
}];
}
When I select an items in collection view, I gather their model's objects, get each id and make array of urls, then in for..in loop i pass urls one by one and then start async download. You can see how I download and call progress method above.
I need to know if you have a reuse issue or a model issue.
So first try this :
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
...
if (![selectedIds.containsObject:selectedId])
{
// Add the selected item into the array
[selectedIds addObject:selectedId];
[selectedVideos addObject:selectedVideo];
AVMVideoCell *collectionCell = (AVMVideoCell*)[collectionView cellForItemAtIndexPath:indexPath];
NSNumber *rowNsNum = [NSNumber numberWithUnsignedInt:(unsigned int)indexPath.row];
if ( ![selecedCellsArray containsObject:[NSString stringWithFormat:#"%#",rowNsNum]] )
{
[selecedCellsArray addObject:[NSString stringWithFormat:#"%ld",(long)indexPath.row]];
collectionCell.selectedBG.hidden = NO;
collectionCell.selectedImg.hidden = NO;
[collectionCell setSelected:YES];
}
}
else {
// Delete the selected item from the array
[selectedIds removeObject:selectedId];
[selectedVideos removeObject:selectedVideo];
AVMVideoCell *collectionCell = (AVMVideoCell*)[collectionView cellForItemAtIndexPath:indexPath];
NSNumber *rowNsNum = [NSNumber numberWithUnsignedInt:(unsigned int)indexPath.row];
if ( [selecedCellsArray containsObject:[NSString stringWithFormat:#"%#",rowNsNum]] )
{
[selecedCellsArray removeObject:[NSString stringWithFormat:#"%ld",(long)indexPath.row]];
collectionCell.selectedBG.hidden = YES;
collectionCell.selectedImg.hidden = YES;
[collectionCell setSelected:NO];
}
}
and remove the didDeselect delegate.
Let me know what happens then.
EDIT :
Ok try this now:
// Lazy instantiation of the progressView
- (UIProgressView *)progressView
{
if (!_progressView)
{
_progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0,0, 150.0f, 1.0f)];
_progressView.trackTintColor = [UIColor colorWithWhite:255 alpha:0.5f];
_progressView.progressTintColor = [UIColor whiteColor];
_progressView.hidden = YES;
[self.contentView addSubview:_progressView];
}
return _progressView;
}
// Here we remove the progressView on reuse
-(void)prepareForReuse
{
[super prepareForReuse];
[self.progressView removeFromSuperview];
self.progressView = nil;
}
Also remove what you did with the progressView with in the cellForItemAtIndexPath method.
You can create class for cell's models, store these models in array in your viewController and use them to get/set all states from/for cells.
Something like this:
#interface CellModel : NSObject
#property(nonatomic) BOOL selected;
#property(nonatomic) NSUInteger progress;
#end
In viewController:
#interface MyViewController () <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic) NSArray* models;
#end

display variable value in UITextField by iOS, Objective-c

Data I need to displayed has been stored into a temp file.When I execute the application, NSLog can receive the data, but UITextField didn't respond. I don't know if I am using the correct syntax. And I am not sure why it doesn't work...
Update: I tried to assign a value to UItextField, but the UItextField doesn't display it neither
-(void)readFilewin
{
// ....
NSString *pathsWin;
NSArray *pathsWin1= NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
pathsWin = [[pathsWin1 objectAtIndex:0] stringByAppendingPathComponent:#"arraycountwin.plist"];
NSArray *getfile = [NSArray arrayWithContentsOfFile:pathsWin];
//NSArray *getfile = [NSArray arrayWithContentsOfFile:#"arraycountwin.plist"];
//self.TotalWinTextField.text = [getfile objectAtIndex:0];
NSString * win = [[NSString alloc]init];
win = [getfile objectAtIndex:0];
NSLog(#"Win : %#", win);
self.TotalWinTextField.text = [NSString stringWithFormat:#"%#", win];
}
-(void)readFileLoss{...}
-(void)readFilestats
{
// ....
NSString *statspath;
NSArray *statspaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
statspath = [[statspaths objectAtIndex:0] stringByAppendingPathComponent:#"arraystats.plist"];
NSArray *getfile = [NSArray arrayWithContentsOfFile:statspath];
NSString * time = [[NSString alloc]init];
time = [getfile objectAtIndex:0];
NSLog(#"Time : %#", time);
NSString * time1 = [[NSString alloc]init];
time1 = [getfile objectAtIndex:1];
NSLog(#"Time1 : %#", time1);
self.textField1.text = time; //broke here after update the viewDidLoad as #paul11 advise
self.textField2.text = time1;
}
Update for testing purpose to make sure the textfield is working, but it cannot even read the assigned value:
- (void)readFilewin
{
self.TotalWinTextField.text = #"23"; //DONT WORK
}
I think you forgot to reference UITextField in the storyboard with your property
#property (weak, nonatomic) IBOutlet UITextField *totalWinTextField;
that is easy you just need to select your UITextField in the storyboard holding down the key control and you drag it to your property. You can see when the property is referenced when in the left side has a circle filled.
I hope to be helpful.
From your comment, this is your viewDidLoad -
- (void)viewDidLoad {
//win
self.TotalWinTextField = 0;
//loss
self.TotalLossTextField = 0;
//stats
self.textField1 = 0;
self.textField2 = 0;
self.textField3 = 0;
[self readFilewin];
[self readFilelose];
[self readFilestats];
}
This is setting all of your IBOutlets to nil (0).
I presume that what you meant was -
- (void)viewDidLoad {
//win
self.TotalWinTextField.text = #"0";
//loss
self.TotalLossTextField.text = #"0";
//stats
self.textField1.text = #"0";
self.textField2.text = #"0";
self.textField3.text = #"0";
[self readFilewin];
[self readFilelose];
[self readFilestats];
}
First of all make sure that outlet is created correctly
Secondly, check it is properly synthesized
thridly, make sure outlet is nonatomic
change ur viewDidLoad to this
- (void)viewDidLoad {
// Do any additional setup after loading the view.
[super viewDidLoad];
//win self.TotalWinTextField = 0;
//loss self.TotalLossTextField = 0;
//stats self.textField1 = 0;
self.textField2 = 0;
self.textField3 = 0;
[self readFilewin];
[self readFilelose];
[self readFilestats];
}

objects in nsmutablearray becoming zombies

i am developing very simple quiz app
In viewDidLoad i am adding objects in myarray
where ever i nslog myarray values it works fine
but if i try this inside ibaction methods all objects becomes zombie
for 2 days i am stuck in this but can't find it what is wrong.
quiz.h
#import <UIKit/UIKit.h>
#import <sqlite3.h>
#class dbVals;
#class viewTransition;
#class AppDelegate;
#interface quiz : UIViewController
{
NSMutableArray *myarray;
IBOutlet UITextView *questionTextView_;
IBOutlet UIButton *skipButton_;
IBOutlet UIButton *optionAButton_;
IBOutlet UIButton *optionBButton_;
IBOutlet UIButton *optionCButton_;
NSString *correctAnswer;
int questionNumber;
int score;
IBOutlet UILabel *scoreLabel_;
int totalQuestions;
}
-(void)populate:(int)number;
//#property(nonatomic, retain) NSMutableArray *myarray;
#property (retain, nonatomic) IBOutlet UITextView *questionTextView;
#property (retain, nonatomic) IBOutlet UIButton *skipButton;
#property (retain, nonatomic) IBOutlet UIButton *optionAButton;
#property (retain, nonatomic) IBOutlet UIButton *optionBButton;
#property (retain, nonatomic) IBOutlet UIButton *optionCButton;
#property (retain, nonatomic) IBOutlet UILabel *scoreLabel;
- (IBAction)optionsToAnswer:(id)sender;
- (IBAction)zzz:(id)sender;
#end
quiz.m
#import "quiz.h"
#import "DbVals.h"
#import "viewTransition.h"
#import "AppDelegate.h"
#implementation quiz
#synthesize skipButton=skipButton_;
#synthesize optionAButton=optionAButton_;
#synthesize optionBButton=optionBButton_;
#synthesize optionCButton=optionCButton_;
#synthesize scoreLabel=scoreLabel_;
#synthesize questionTextView=questionTextView_;
//#synthesize myarray;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)createEditableCopyOfDatabaseIfNeeded
{
//NSLog(#"Creating editable copy of database");
// First, test for existence.
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"oq.sqlite"];
success = [fileManager fileExistsAtPath:writableDBPath];
if (success) return;
// The writable database does not exist, so copy the default to the appropriate location.
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"oq.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
+(sqlite3 *) getNewDBConnection
{
sqlite3 *newDBconnection;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"oq.sqlite"];
// Open the database. The database was prepared outside the application.
if (sqlite3_open([path UTF8String], &newDBconnection) == SQLITE_OK) {
//NSLog(#"Database Successfully Opened ");
} else {
NSLog(#"Error in opening database ");
}
return newDBconnection;
}
- (void)viewDidLoad
{
[super viewDidLoad];
questionNumber = 0;
score = 0;
[self createEditableCopyOfDatabaseIfNeeded];
sqlite3 *dbc = [quiz getNewDBConnection];
sqlite3_stmt *statement = nil;
const char *sqlSelect = "select * from QnA ORDER BY RANDOM()";
if(sqlite3_prepare_v2(dbc, sqlSelect, -1, &statement, NULL)!=SQLITE_OK)
{
NSAssert1(0, #"Error Preparing Statement", sqlite3_errmsg(dbc));
}
else
{
myarray = [[NSMutableArray alloc]init];
while(sqlite3_step(statement)==SQLITE_ROW)
{
NSString *q = [NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 0)];
NSString *o = [NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 1)];
NSString *a = [NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 2)];
DbVals *dbValsObj = [[DbVals alloc]init];
[dbValsObj setValsOfQuestions:q options:o answer:a];
[myarray addObject:dbValsObj];
[dbValsObj release];
}
}
sqlite3_finalize(statement);
//[self populate:questionNumber];
}
-(void)populate:(int)number
{
/*[scoreLabel_ setText:[NSString stringWithFormat:#"%d",score]];
AppDelegate *appDel = [[UIApplication sharedApplication] delegate];
[appDel setFinalScore:[NSString stringWithFormat:#"%d",score]];
if(number < [myarray count])
{
DbVals *dbv1 = [myarray objectAtIndex:number];
[questionTextView_ setText:[dbv1 getQuestions]];
NSString *joinedOptions = [dbv1 getOptions];
NSArray *splitOptions = [joinedOptions componentsSeparatedByString:#","];
[optionAButton_ setTitle:[splitOptions objectAtIndex:0] forState:UIControlStateNormal];
[optionBButton_ setTitle:[splitOptions objectAtIndex:1] forState:UIControlStateNormal];
[optionCButton_ setTitle:[splitOptions objectAtIndex:2] forState:UIControlStateNormal];
correctAnswer = [dbv1 getAnswer];
}
else
{
//viewTransition *vt = [[viewTransition alloc]init];
[viewTransition viewsTransitionCurrentView:self toNextView:#"result"];
//[vt release];
}*/
}
- (void)viewDidUnload
{
for(int i=0; i<[myarray count]; i++)
{
DbVals *dbv1 = [myarray objectAtIndex:i];
NSLog(#"%#",[dbv1 getQuestions]);
NSLog(#"%#",[dbv1 getOptions]);
NSLog(#"%#",[dbv1 getAnswer]);
NSLog(#"<u><u><u><u><><><><><><><><><><><>");
}
[self setQuestionTextView:nil];
[questionTextView_ release];
questionTextView_ = nil;
[self setQuestionTextView:nil];
[skipButton_ release];
skipButton_ = nil;
[self setSkipButton:nil];
[optionAButton_ release];
optionAButton_ = nil;
[self setOptionAButton:nil];
[optionBButton_ release];
optionBButton_ = nil;
[self setOptionBButton:nil];
[optionCButton_ release];
optionCButton_ = nil;
[self setOptionCButton:nil];
[scoreLabel_ release];
scoreLabel_ = nil;
[self setScoreLabel:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc
{
for(int i=0; i<[myarray count]; i++)
{
DbVals *dbv1 = [myarray objectAtIndex:i];
NSLog(#"%#",[dbv1 getQuestions]);
NSLog(#"%#",[dbv1 getOptions]);
NSLog(#"%#",[dbv1 getAnswer]);
NSLog(#"<d><d><d><d><d><><><><><><><><><><>");
}
[questionTextView_ release];
[skipButton_ release];
[optionAButton_ release];
[optionBButton_ release];
[optionCButton_ release];
[scoreLabel_ release];
[myarray release];
[super dealloc];
}
- (IBAction)optionsToAnswer:(id)sender
{
for(int i=0; i<[myarray count]; i++)
{
DbVals *dbv1 = [myarray objectAtIndex:i];
NSLog(#"%#",[dbv1 getQuestions]);
NSLog(#"%#",[dbv1 getOptions]);
NSLog(#"%#",[dbv1 getAnswer]);
NSLog(#"six");
}
if(sender == skipButton_)
{
//questionNumber++;
//[self populate:questionNumber];
/*[UIView animateWithDuration:5 delay:0 options: UIViewAnimationCurveEaseOut
animations:
^{
[UIView setAnimationTransition:103 forView:self.view cache:NO];
}
completion:
^(BOOL finished)
{
}
];*/
}
if(sender == optionAButton_)
{
/*NSString *one = #"1";
if([correctAnswer isEqualToString:one])
{
score++;
}
questionNumber++;
[self populate:questionNumber];*/
}
if(sender == optionBButton_)
{
/*NSString *two = #"2";
if([correctAnswer isEqualToString:two])
{
score++;
}
questionNumber++;
[self populate:questionNumber];*/
}
if(sender == optionCButton_)
{
/*NSString *three = #"3";
if([correctAnswer isEqualToString:three])
{
score++;
}
questionNumber++;
[self populate:questionNumber];*/
}
}
- (IBAction)zzz:(id)sender
{
}
#end
dbVals.h
#import <Foundation/Foundation.h>
#interface DbVals : NSObject
{
NSString *questions_;
NSString *options_;
NSString *answer_;
// NSString *hint;
// NSString *mode;
}
-(void)setValsOfQuestions:(NSString*)questions options:(NSString*)options answer:(NSString*)answer;
-(NSString*)getQuestions;
-(NSString*)getOptions;
-(NSString*)getAnswer;
dbVals.m
#import "DbVals.h"
#implementation DbVals
-(void)setValsOfQuestions:(NSString*)questions options:(NSString*)options answer:(NSString*)answer
{
questions_ = questions;
options_ = options;
answer_ = answer;
}
-(NSString*)getQuestions
{
return questions_;
}
-(NSString*)getOptions
{
return options_;
}
-(NSString*)getAnswer
{
return answer_;
}
#end
Your dbVals.m setVals isn't retaining the parameters. This obviously means, everything inside becomes deallocated once the function scope ends.
Try changing it to something like
-(void)setValsOfQuestions:(NSString*)questions options:(NSString*)options answer:(NSString*)answer
{
[questions_ release];
[options_ release];
[answer_ release];
questions_ = [questions copy];
options_ = [options copy];
answer_ = [answer copy];
}

Resources