ios Pass an object between more than 2 view controllers - ios

I have my classe which contains my data Data
I created my object in my first View called ViewController
I will create others viewControllers and I want to read and write datas in the object "man1" created in my ViewController.
How can I do that ?
Thank you very much.
This is my code so far:
Data.H
#import <Foundation/Foundation.h>
#interface Data : NSObject
{
NSString *name;
int age;
NSString *city;
}
- (id)initWithName:(NSString *)aName ;
- (NSString*) name;
- (int) age;
- (NSString*) city;
//- (void) setPrenom:(NSString*) prenom;
- (void) setName:(NSString*) newName;
- (void) setAge:(int) newAge;
- (void) setCity:(NSString*) newCity;
#end
Data.m
#import "Data.h"
#implementation Data
- (id)initWithName:(NSString *)aName
{
if ((self = [super init]))
{
self.name = aName;
}
return self;
}
//getter
- (NSString*) name
{
return name;
}
- (int) age{
return age;
}
- (NSString*) city{
return city;
}
//setter
- (void) setName:(NSString*)newName
{
name = newName;
}
- (void) setAge:(int) newAge
{
age = newAge;
}
- (void) setCity:(NSString *)newCity
{
city = newCity;
}
#end
ViewController.h
#import <UIKit/UIKit.h>
#import "Data.h"
#interface ViewController : UIViewController
{
int testint;
}
#property (readwrite) Data *man1;
#property (weak, nonatomic) IBOutlet UILabel *labelAff;
#end
ViewController.m
#import "ViewController.h"
#import "Data.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize man1 = _man1;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSString * name1 = #"Bob";
_man1 = [[Data alloc]initWithName:name1 ];
NSLog(#" %# ", _man1.name);
[_man1 setAge:29];
NSLog(#" %d ", _man1.age);
[_man1 setCity:#"Tapei"];
_labelAff.text = [_man1 city];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end

Your approach is not going to work, because you allocate a new instance of Data each time a view is loaded, and because each view controller gets its own Data object.
One approach to fixing this is making your Data class a singleton. Your view controllers will be accessing a single instance of Data, ensuring that the information is shared among the view controllers:
Data.h
#interface Data : NSObject
{
NSString *name;
int age;
NSString *city;
}
- (id)initWithName:(NSString *)aName ;
- (NSString*) name;
- (int) age;
- (NSString*) city;
- (void) setName:(NSString*) newName;
- (void) setAge:(int) newAge;
- (void) setCity:(NSString*) newCity;
+(Data*)instance;
#end
Data.m
#implementation Data
-(id)initWithName:(NSString *)aName {
if(self=[super init]) {
...
}
return self;
}
+(Data*)instance {
static dispatch_once_t once;
static Data *sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] initWithName: ...];
});
return sharedInstance;
}
#end

Related

How to create a custom class with multiple keys and objects like NSMutableDictionary

I am a newbie to Objective C. I would like to create a class that has a nested class in it. To my knowledge, there is nothing like nested classes.
I would like it to be like an NSArray of NSMutableDictionary.
So far I have two different custom classes, where one is supposed to be nested in the other.
Group.h
#import "Category.h"
#interface Group : NSObject
- (instancetype)initWithGroupName:(NSString *)groupName
- (Category *)category;
#end
Group.m
#interface Group ()
#property(nonatomic, strong) NSString *groupName;
#end
#implementation Group
- (instancetype)initWithGroupName:(NSString *)groupName {
self = [super init];
if (self) {
self.groupName = groupName;
self.payID = paymentID;
self.sort = sortOrder;
}
return self;
}
- (NSString *)name {
return self.groupName;
}
- (Category *)category {
Category *test = [[Category alloc] init];
return test;
}
Category.h
#interface Category : NSObject
- (instancetype)initWithCategoryName:(NSString *)name
withDescription:(NSString *)description
ofPercent:(int)percent;
- (NSString *)name;
- (NSString *)description;
- (NSString *)percent;
#end
Category.m
#interface Category ()
#property(nonatomic, strong) NSString *title;
#property(nonatomic, strong) NSString *descrip;
#property(assign) int perc;
#end
#implementation Category
- (instancetype)initWithCategoryName:(NSString *)name
withDescription:(NSString *)description
ofPercent:(int)percent {
self = [super init];
if (self) {
self.title = name;
self.descrip = description;
self.perc = percent;
}
return self;
}
- (NSString *)name {
return self.title;
}
- (NSString *)description {
return self.descrip;
}
- (NSString *)percent {
return [[NSString stringWithFormat:#"%d", self.perc * 100] stringByAppendingString:#"%"];
}
#end
I am not sure how to make it work. What exactly I want to do is to have one Group with many categories in it or one group that has 4 subgroups with many categories in each subgroups.
Thanks in advance for any help!

KVO on NSObject not working for some reason

I'm trying to implement KVOController in my app. I managed to get it working on custom UISliders, but I can't seem to get it working on a custom NSObject. This is the object:
Restaurant.h
#import <UIKit/UIKit.h>
#interface Restaurant : NSObject
#property (nonatomic, copy, readonly) NSString *name, *tagline;
#property (nonatomic, copy, readonly) UIColor *uicolor;
- (id)initWithName:(NSString *)main;
- (void)setName:(NSString *)title;
- (void)changeColor:(UIColor)color;
#end
Restaurant.m
#implementation Restaurant
- (id)initWithName:(NSString *)main {
self = [super init];
if (self)
{
_name = main;
}
return self;
}
- (void)setName:(NSString *)title {
_name = title;
}
- (void)changeColor:(UIColor)color {
_uicolor = color;
}
#end
So, I introduced this listener into my code:
- (void)viewDidLoad {
[super viewDidLoad];
self.restaurant = [[Restaurant alloc] initWithName:#"test"];
[self.restaurant changeColor:[UIColor blueColor]];
FBKVOController *KVOController = [FBKVOController controllerWithObserver:self];
self.KVOController = KVOController;
[self.KVOController observe:self.restaurant keyPath:#"name" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew block:^(id observer, id object, NSDictionary *change) {
NSLog(#"Restaurant changed!");
}];
}
- (void)someOtherMethod:(id)sender {
[self.restaurant setName:#"Another test"];
[self.restaurant changeColor:[UIColor redColor]];
}
However, this isn't logging anything for this, nor when I change the keyPath to #"uicolor". What am I doing wrong?

iOS NSKeyedUnarchiver not get correct value

I simplify the code for ask question.
I want to save more class and load class model file.
But now I simplify parameters to one part (lim) in the model(FlightSettingModel.h).
In the FlightSettingModel.h I have set some parameters in here.
FlightSettingModel.h code below:
#import <Foundation/Foundation.h>
#interface FlightSettingModel : NSObject<NSCoding>
// lim property part
#property float limCurrentVal;
#property float limDefaultVal;
#property float limMaxVal;
#property float limMinVal;
// .... other property part
#end
FlightSettingModel.m code below
#import "FlightSettingModel.h"
#interface FlightSettingModel()
{
}
#end
#implementation FlightSettingModel
-(instancetype)init
{
self = [super init];
if(self)
{
self.limDefaultVal = 3.0;
self.limCurrentVal = 4.0;
self.limMaxVal = 10;
self.limMinVal = 0;
// ... other property part value init .....
}
return self;
}
- (void)setFlightSettingToDefaultValue
{
self.limCurrentVal = self.limDefaultVal;
}
- (void) encodeWithCoder: (NSCoder *)encoder
{
[encoder encodeFloat:self.limCurrentVal forKey:#"limCurrentVal"];
}
- (id)initWithCoder:(NSCoder *)decoder {
if((self = [super init])) {
self.limCurrentVal = [decoder decodeFloatForKey:#"limCurrentVal"];
}
return self;
}
#end
Then I have set the singleton SettingData file to initial the FlightSettingModel and other model class.
The SettingData model header like below:
#import <Foundation/Foundation.h>
#import "FlightSettingModel.h"
#interface SettingData : NSObject
#property (nonatomic,strong) FlightSettingModel *flightSettingModel;
+(SettingData*) sharedInstance;
#end
SettingData.m code below:
#import "SettingData.h"
#implementation SettingData
SettingData *sharedInstance;
+(SettingData*) sharedInstance{
if( sharedInstance == nil )
{
sharedInstance = [SettingData new];
}
return sharedInstance;
}
-(id) init{
self = [super init];
if( self )
{
self.flightSettingModel = [FlightSettingModel new];
}
return self;
}
#end
In my storyboard (UI) is like below:
When I click the save button , I want to save the custom class model(FlightSettingModel.h) in the NSKeyedArchiver. When I click the load, I want to load the model from the archiver using NSKeyedUnarchiver and resetting to the slider.
But now,when I drag the slider to other value(ex:10), then I click the save, then I close the app restart the app. I click the load, the slider value will become 0.
I don't know why when I load the value the all value will become 0;
My view controller code .m below:
#import "ViewController.h"
#import "SettingData.h"
#interface ViewController ()
{
NSString *path;
NSString *fileName;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// file manage
path =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) objectAtIndex:0];
fileName = [path stringByAppendingPathComponent:#"flightFile"];
[self setUIValue];
NSLog(#"---");
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (IBAction)saveAction:(UIButton *)sender {
[NSKeyedArchiver archiveRootObject:[SettingData sharedInstance].flightSettingModel toFile:fileName];
}
- (IBAction)loadAction:(UIButton *)sender {
[SettingData sharedInstance].flightSettingModel = (FlightSettingModel*) [NSKeyedUnarchiver unarchiveObjectWithFile: fileName];
[self setUIValue];
NSLog(#"current Value:%.f",[SettingData sharedInstance].flightSettingModel.limCurrentVal);
}
- (IBAction)sliderChangedAction:(UISlider *)sender {
[SettingData sharedInstance].flightSettingModel.limCurrentVal = sender.value;
self.theTextField.text = [NSString stringWithFormat:#"%.f",self.theSlider.value];
}
-(void) setUIValue
{
// setting slider property
self.theSlider.maximumValue = [SettingData sharedInstance].flightSettingModel.limMaxVal;
self.theSlider.minimumValue = [SettingData sharedInstance].flightSettingModel.limMinVal;
self.theSlider.value = [SettingData sharedInstance].flightSettingModel.limCurrentVal;
self.theTextField.text = [NSString stringWithFormat:#"%.f",self.theSlider.value];
}
#end
Have anyone know where my problem in my code?
thank you very much.
If you want to download the complete code(the question code) , I have upload in github
This behavior happens because the [SettingData sharedInstance].flightSettingModel.limMaxVal and the [SettingData sharedInstance].flightSettingModel.limMinVal are zero:
-(void) setUIValue
{
// setting slider property
self.theSlider.maximumValue = [SettingData sharedInstance].flightSettingModel.limMaxVal;
// self.theSlider.maximumValue = 0
self.theSlider.minimumValue = [SettingData sharedInstance].flightSettingModel.limMinVal;
// self.theSlider.minimumValue = 0
self.theSlider.value = [SettingData sharedInstance].flightSettingModel.limCurrentVal;
// [SettingData sharedInstance].flightSettingModel.limCurrentVal = 10
self.theTextField.text = [NSString stringWithFormat:#"%.f",self.theSlider.value];
}
EDIT: You can fix it by adding this:
- (void) encodeWithCoder: (NSCoder *)encoder {
[encoder encodeFloat:self.limCurrentVal forKey:#"limCurrentVal"];
[encoder encodeFloat:self.limMaxVal forKey:#"limMaxVal"];
[encoder encodeFloat:self.limMinVal forKey:#"limMinVal"];
}
- (id)initWithCoder:(NSCoder *)decoder {
if((self = [super init])) {
self.limCurrentVal = [decoder decodeFloatForKey:#"limCurrentVal"];
self.limMaxVal = [decoder decodeFloatForKey:#"limMaxVal"];
self.limMinVal = [decoder decodeFloatForKey:#"limMinVal"];
}
return self;
}

no visible #interface eror in objective-c

I can't figure out why the problem described here is happening.
This my student.h:
#import <Foundation/Foundation.h>
#interface Student : NSObject
#property NSString* fName;
#property NSString* lName;
#property NSString* studentId;
#property NSString* phoneNum;
#property NSString* degree;
-(id) init: (NSString*)fName lName:(NSString*)lName sId:(NSString*)sId pn:(NSString*)pn degree: (NSString*) degree;
#end
This is my student.m:
#import "Student.h"
#implementation Student
-(id) init: (NSString*)fName lName:(NSString*)lName sId:(NSString*)sId pn:(NSString*)pn degree: (NSString*) degree
{
self = [super init];
if(self){
self.fName = fName;
self.lName = lName;
self.studentId = sId;
self.phoneNum = pn;
self.degree = degree;
}
return self;
}
#end
And this is my main:
#import <Foundation/Foundation.h>
#import "Student.h"
#import "StudentDB.h"
int main(int argc, const char * argv[]) {
#autoreleasepool {
// insert code here...
NSLog(#"Hello, World!");
Student* ignacio =[[Student alloc] init: #"ignacio" lName: #"cooper" sId: #"123456" pn:#"01234" degree:#"Computer science"];
[[StudentDB instance] addStudents: ignacio];
}
return 0;
}
The error is happening in this line:
Student* ignacio =[[Student alloc] init: #"ignacio" lName: #"cooper" sId: #"123456" pn:#"01234" degree:#"Computer science"];
Here's the entire error:
no visible #interface for 'Student' declares the selector 'init:lName:sId:pn:degree'
Without the StudentDB it works fine. It appears the trouble is there, but I can't find it. Can anyone give me an idea on how I can solve this?
Here are my StudentDB.h and StudentDB.m:
#import "StudentDB.h"
#implementation StudentDB
static StudentDB* instance = nil;
-(id)init
{
self = [super init];
if(self){
self.students = [[NSMutableArray alloc] init];
}
return self;
}
+ (StudentDB*) instance
{
if(instance == nil){
instance = [[StudentDB alloc] init];
}
return instance;
}
-(void) addStudents:(Student *)s
{
[self.students addObject: s];
}
-(Student*) getStudent:(NSString*)sId
{
for(Student* s in self.students)
{
if(s.studentId == sId)
return s;
}
return nil;
}
-(void) deleteStudent:(NSString*)sId
{
for(Student* s in self.students)
{
if(s.studentId == sId){
[self.students removeObject:s];
break;
}
}
}
-(void) updateStudent:(Student*)s
{
[self deleteStudent: s.studentId];
[self addStudents:s];
}
#end
#import <Foundation/Foundation.h>
#import "Student.h"
#interface StudentDB : NSObject
#property NSMutableArray* students;
+(StudentDB*) instance;
-(id)init;
-(void) addStudents:(Student *)s;
-(Student*) getStudent:(NSString*)sId;
-(void) deleteStudent:(NSString*)sId;
-(void) updateStudent:(Student*)s;
#end

How to keep a variable in memory until the app quits

I have a singleton object in iOS that when instantiated parses a CSV file and then holds the results. I would like to make this object universally accessible and I would like it to not be released from memory until the app quits. I am running ARC so I cannot do manual retains.
Is there a way I can do this so it will work with ARC?
Header File:
#import <Foundation/Foundation.h>
#import "CHCSV.h"
#import "RCParserObject.h"
#interface ParserStore : NSObject <CHCSVParserDelegate>
{
// CSV Variables
RCParserObject *item;
NSMutableArray *data;
NSMutableArray *parsedData;
int fields;
bool open;
}
#property (atomic, retain) RCParserObject *item;
#property (atomic, retain) NSMutableArray *data;
#property (atomic, retain) NSMutableArray *parsedData;
#property (atomic) int fields;
#property (atomic) bool open;
+ (ParserStore *) defaultStore;
- (void) parseCSVFile:(NSString*)file;
- (void) categorizeData;
Implementation File
#import "ParserStore.h"
#import "RCParserObject.h"
#import "RCDetailItem.h"
static ParserStore *defaultStore;
#implementation ParserStore
#synthesize item, data, parsedData, fields, open;
# pragma mark -
# pragma mark Singleton Methods
+ (ParserStore *) defaultStore
{
if (!defaultStore)
{
defaultStore = [[super allocWithZone:NULL] init];
}
return defaultStore;
}
+ (id) allocWithZone:(NSZone *)zone
{
return [self defaultStore];
}
- (id) init
{
NSLog(#"Running init on parser store");
if (defaultStore)
{
NSLog(#"Self data count is %d, right before return", self.parsedData.count);
return defaultStore;
}
// NSLog(#"This better only happen once");
self = [super init];
[self setParsedData:[[NSMutableArray alloc] init]];
[self parseCSVFile:#"ContentNoPathFileExt2ASCII"];
[self categorizeData];
// NSLog(#"Self data count is %d when first created", self.parsedData.count);
return self;
}
#property (atomic, retain) RCParserObject *item;
#property (atomic, retain) NSMutableArray *data;
#property (atomic, retain) NSMutableArray *parsedData;
#property (atomic) int fields;
#property (atomic) bool open;
+ (ParserStore *) defaultStore;
- (void) parseCSVFile:(NSString*)file;
- (void) categorizeData;
#end
+(MySingleton *)singleton {
static dispatch_once_t pred;
static MySingleton *shared = nil;
dispatch_once(&pred, ^{
shared = [[MySingleton alloc] init];
shared.someVar = someValue; // if you want to initialize an ivar
});
return shared;
}
From anywhere:
NSLog(#"%#",[MySingleton singleton].someVar);
Note that your iOS app already has a singleton that you can access anywhere:
AppDelegate *delegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
a simple singleton would be something like... in the .h:
#interface Foo : NSObject
+ (Foo *)sharedInstance;
#end
and in the .m:
static Foo *_foo = nil;
#implementation Foo
+ (Foo *)sharedInstance {
if (!_foo)
_foo = [[Foo alloc] init];
return _foo;
}
#end

Resources