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?
Related
[__NSArrayM insertObject:atIndex:]: object cannot be nil
The problem is when trying to execute [_eventsArray addObject:eventModel]; error is occurred.
eventModel is nil.
How can I solve this problem ?
#import "ViewController.h"
#interface ViewController ()
#property (nonatomic, strong) NSMutableArray *eventsArray;
#end
#interface EventsModel : NSObject
#property(nonatomic, assign) NSString *title;
#property(nonatomic, strong) NSString *details;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
EventsModel *eventModel ;
eventModel.title = #"Meeting";
eventModel.details = #"some description";
[_eventsArray addObject:eventModel];
}
#end
#pragma mark - Model Class
#implementation EventsModel
-(instancetype)init{
self = [super init];
if (self) {
self.title = nil;
self.details =nil;
}
return self;
}
#end
EventsModel *model = [EventsModel new];
model.title = #"test";
model.details = #"Detail test";
EventsModel *model2 = [EventsModel new];
model2.title = #"test2";
model2.details = #"Detail test2";
[_eventsArray addObject:model];
[_eventsArray addObject:model2];
NSLog(#"%lu elements in array",(unsigned long)_eventsArray.count);
you use EventsModel *model = [EvenntsModel new]; and create object
try this code
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!
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;
}
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
I have gone through a few tutorials including the sample app included
with Three20 and cannot figure out why photos aren't showing up in my
TTPhotoViewController. I actually find it pretty hard to debug.
Below is the code I have. Any thoughts on why images will not load
and how to debug it would be great. I get a completely black view in
between my bottom tabbar and upper nav bar. I also see left and right
arrows overlayed on the black view which seems to be for navigating
photos although I thought it was supposed to display a thumbnail
gallery.
// A TTPhoto class
// Photo.h
#import <Foundation/Foundation.h>
#import <Three20/Three20.h>
#interface Photo : NSObject <TTPhoto> {
NSString *_caption;
NSString *_urlLarge;
NSString *_urlSmall;
NSString *_urlThumb;
id <TTPhotoSource> _photoSource;
CGSize _size;
NSInteger _index;
}
#property (nonatomic, copy) NSString *caption;
#property (nonatomic, copy) NSString *urlLarge;
#property (nonatomic, copy) NSString *urlSmall;
#property (nonatomic, copy) NSString *urlThumb;
#property (nonatomic, assign) id <TTPhotoSource> photoSource;
#property (nonatomic) CGSize size;
#property (nonatomic) NSInteger index;
- (id)initWithCaption:(NSString *)caption urlLarge:(NSString
*)urlLarge urlSmall:(NSString *)urlSmall urlThumb:(NSString *)urlThumb
size:(CGSize)size;
#end
// Photo.m
#import "Photo.h"
#implementation Photo
#synthesize caption = _caption;
#synthesize urlLarge = _urlLarge;
#synthesize urlSmall = _urlSmall;
#synthesize urlThumb = _urlThumb;
#synthesize photoSource = _photoSource;
#synthesize size = _size;
#synthesize index = _index;
- (id)initWithCaption:(NSString *)caption urlLarge:(NSString
*)urlLarge urlSmall:(NSString *)urlSmall urlThumb:(NSString *)urlThumb
size:(CGSize)size {
if ((self = [super init])) {
self.caption = caption;
self.urlLarge = urlLarge;
self.urlSmall = urlSmall;
self.urlThumb = urlThumb;
self.size = size;
self.index = NSIntegerMax;
self.photoSource = nil;
}
return self;
}
- (void) dealloc {
self.caption = nil;
self.urlLarge = nil;
self.urlSmall = nil;
self.urlThumb = nil;
[super dealloc];
}
#pragma mark TTPhoto
- (NSString*)URLForVersion:(TTPhotoVersion)version {
switch (version) {
case TTPhotoVersionLarge:
return _urlLarge;
case TTPhotoVersionMedium:
return _urlLarge;
case TTPhotoVersionSmall:
return _urlSmall;
case TTPhotoVersionThumbnail:
return _urlThumb;
default:
return nil;
}
}
#end
// A TTPhotoSource class
// PhotoSet.h
#import <Foundation/Foundation.h>
#import "Three20/Three20.h"
#interface PhotoSet : TTURLRequestModel <TTPhotoSource> {
NSString *_title;
NSArray *_photos;
NSArray* _tempPhotos;
NSTimer* _fakeLoadTimer;
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, retain) NSArray *photos;
- (id) init;
#end
// PhotoSet.m
#import "PhotoSet.h"
#import "Photo.h"
#implementation PhotoSet
#synthesize title = _title;
#synthesize photos = _photos;
- (id) init {
_title = #"Test photo album";
_photos = [[NSArray alloc] initWithObjects:
[[[Photo alloc] initWithCaption:#"coming soon"
urlLarge:#"http://farm5.static.flickr.com/
4066/4653156849_0905e6b58e_o.jpg"
urlSmall:#"http://farm5.static.flickr.com/
4066/4653156849_0d15f0e3f0_s.jpg"
urlThumb:#"http://farm5.static.flickr.com/
4066/4653156849_0d15f0e3f0_s.jpg"
size:CGSizeMake(220, 112)] autorelease],
[[[Photo alloc] initWithCaption:#"coming soon 2"
urlLarge:#"http://farm5.static.flickr.com/
4023/4653774402_05e6acd995_o.jpg"
urlSmall:#"http://farm5.static.flickr.com/
4009/4653157237_c2f5f59e0d_s.jpg"
urlThumb:#"http://farm5.static.flickr.com/
4009/4653157237_c2f5f59e0d_s.jpg"
size:CGSizeMake(220, 112)] autorelease],
[[[Photo alloc] initWithCaption:#"coming soon 2"
urlLarge:#"http://farm5.static.flickr.com/
4023/4653774402_05e6acd995_o.jpg"
urlSmall:#"http://farm5.static.flickr.com/
4009/4653157237_c2f5f59e0d_s.jpg"
urlThumb:#"http://farm5.static.flickr.com/
4009/4653157237_c2f5f59e0d_s.jpg"
size:CGSizeMake(220, 112)] autorelease],
[[[Photo alloc] initWithCaption:#"coming soon 2"
urlLarge:#"http://farm5.static.flickr.com/
4023/4653774402_05e6acd995_o.jpg"
urlSmall:#"http://farm5.static.flickr.com/
4009/4653157237_c2f5f59e0d_s.jpg"
urlThumb:#"http://farm5.static.flickr.com/
4009/4653157237_c2f5f59e0d_s.jpg"
size:CGSizeMake(220, 112)] autorelease],
nil];
for (int i = 0; i < _photos.count; ++i) {
id<TTPhoto> photo = [_photos objectAtIndex:i];
if ((NSNull*)photo != [NSNull null]) {
NSLog(#"in here 65434");
photo.photoSource = self;
photo.index = i;
}
}
return self;
}
- (void) dealloc {
self.title = nil;
self.photos = nil;
[super dealloc];
}
#pragma mark TTModel
- (BOOL)isLoading {
return NO;
}
- (BOOL)isLoaded {
return YES;
}
#pragma mark TTPhotoSource
- (NSInteger)numberOfPhotos {
return _photos.count;
}
- (NSInteger)maxPhotoIndex {
return _photos.count-1;
}
- (id<TTPhoto>)photoAtIndex:(NSInteger)photoIndex {
if (photoIndex < _photos.count) {
return [_photos objectAtIndex:photoIndex];
} else {
return nil;
}
}
#end
// A TTPhotoViewController
// EventDetailViewController.h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <Three20/Three20.h>
#import "PhotoSet.h"
#class Event;
#interface EventDetailViewController :
TTPhotoViewController<UINavigationControllerDelegate,
UIImagePickerControllerDelegate> {
NSArray *photos;
Event *event;
PhotoSet *_photoSet;
}
#property (nonatomic, retain) NSArray *photos;
#property (nonatomic, retain) Event *event;
#property (nonatomic, retain) PhotoSet *photoSet;
- (id)initWithEvent:(Event *)e;
// EventDetailViewController.m
#import "EventDetailViewController.h"
#import "Event.h"
#import "PhotoSet.h"
#import "Photo.h"
#implementation EventDetailViewController
#synthesize photos;
#synthesize event;
#synthesize photoSet = _photoSet;
#pragma mark -
#pragma mark Initialization
- (void)viewDidLoad {
self.photoSet = [[PhotoSet alloc] init];
self.photoSource = self.photoSet;
}
- (id)initWithEvent:(Event *)e {
if (self) {
self.event = e;
}
return self;
}
#end
You may find an answer here: http://www.raywenderlich.com/1430/how-to-use-the-three20-photo-viewer