Changing an NSObject inside of a NSMutableArray from a Singleton - ios

I have a singleton which looks like this:
#implementation BARTicketManager
+ (BARTicketManager *)sharedManager {
static dispatch_once_t pred;
static BARTicketManager *shared = nil;
dispatch_once(&pred, ^{
shared = [[BARTicketManager alloc] initUniqueInstance];
});
return shared;
}
- (id) initUniqueInstance {
if (self = [super init]) {
/* holds the list of TicketPurchase objects */
_ticket_list = [[NSMutableArray alloc] init];
}
return self;
}
The _ticket_list above is declared as:
#property (nonatomic, retain) NSMutableArray *ticket_list;
This list holds objects of type TicketPurchase. A method inside of TicketPurchase is 'setTicketAsReserved' as follows:
- (void) setTicketAsReserved:(NSDate *)reserved_datetime {
_status = RESERVED;
_reserved_datetime = reserved_datetime;
}
The problem I am having, is that when I run through the objects in the _ticket_list and call 'setTicketAsReserved' on some of those objects, and then attempt to access them by calling the singleton again, the value for _reserved_datetime is not saved, whereas the value of _status IS saved.
Can anyone understand why this would be the case?
Edit:
Relevant declarations for TicketPurchase:
#property (weak, nonatomic) NSDate *reserved_datetime;
#property (nonatomic) TicketStatus status;

Since your reserved_datetime property is declared weak, it's likely getting deallocated. Try changing that declaration to strong, since you want the TicketPurchase class to keep the reserved_datetime property around.

Related

Property 'levelCompleted' not found on object of type 'id'

Here's my model class LevelInformationModel.
#interface LevelInformationModel : NSObject
#property NSInteger levelCompleted;
+(id)sharedModel;
#end
#import "LevelInformationModel.h"
#implementation LevelInformationModel
#synthesize levelCompleted;
/* Return singleton model */
+ (id)sharedModel {
static LevelInformationModel *sharedModel = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedModel = [[self alloc] init];
});
return sharedModel;
}
- (id)init {
self = [super init];
if (self) {
self.levelCompleted = 0;
}
return self;
}
#end
And here's how I'm using it all (in GameViewController class). I have imported LevelInformationModel.h already.
NSInteger currentLevel = [LevelInformationModel sharedModel].levelCompleted;
But above the levelCompleted property is the error Property 'levelCompleted not found on type 'id'`. Any thoughts would be great.
That's because your method is returning an id.
Change it to this
+(LevelInformationModel)sharedModel
{
.
You should use
+(instancetype)sharedModel;
"There definitely is a benefit. When you use 'id', you get essentially no type checking at all. With instancetype, the compiler and IDE know what type of thing is being returned, and can check your code better and autocomplete better."
Would it be beneficial to begin using instancetype instead of id?
https://developer.apple.com/library/ios/releasenotes/ObjectiveC/ModernizationObjC/AdoptingModernObjective-C/AdoptingModernObjective-C.html

Initialize Public class via private category

I am building an SDK, and I have a class that I want to be public to the users, but I do not want them creating this object themselves. The method I came up with to solve this is by having a private category on the object and doing my initialization of this object in the category. Additionally the properties in the public header are readonly because I also don't want the users modifying the objects they receive. What I have in the category .h looks like this:
#property (nonatomic, readwrite) NSString *property;
- (instancetype)initWithData:(NSDictionary *)data;
And the .m looks like this:
#implementation MyObject (Category)
- (instanceType)initWithData:(NSDictionary *)data {
self = [super init];
if (self) {
MyObject *object = [[MyObject alloc] init];
NSLog(#"Object created");
[object setProperty:data[#"property"];
NSLog(#"Property set");
}
return self;
}
- (void)setProperty:(NSString *)property {
self.property = property;
}
This code prints the "object created" statement, but not the "property set" statement. The UI of my app then locks up and there is no error or crash returned. So my question is, how do I get these properties to be set for this custom object?

RLMObject unable to use as a normal object

I have a Product model with the header:
#interface Product : RLMObject <NSCopying,NSCoding>
{
}
#property (nonatomic, strong) NSString *title;
#property (nonatomic, strong) NSString *thumbnailURL;
#property (nonatomic, strong) UIImage *thumbnail;
-(id)initWithInfo:(NSDictionary*)dictionary;
-(UIImage*)getThumbnail;
and implementation:
#implementation Product
-(id)initWithInfo:(NSDictionary*)dictionary
{
self = [self init];
if (self) {
_title = dictionary[#"title"];
_thumbnailURL = dictionary[#"thumbnailURL"];
_thumbnail = [self getThumbnail];
}
return self;
}
-(UIImage*)getThumbnail
{
if (_thumbnail) {
return _thumbnail;
}
//load image from cache
return [self loadImageFromCache];
}
Now, when I try to create a Product object and insert it into Realm, I always get the exception
[RLMStandalone_Product getThumbnail]: unrecognized selector sent to instance 0xcd848f0'
Now, I remove _thumbnail = [self getThumbnail]; and it works fine. But then I get another exception
[RLMStandalone_Product title]: unrecognized selector sent to instance 0xd06d5f0'
when I reload my view. I have created my Product object in the main thread, so it should be fine to using its property and method, isn't it?
Any advice will be appreciated!
Because Realm object properties are backed by the database rather than in-memory ivars, accessing those properties' ivars is not supported. We're currently clarifying our docs to convey this:
Please note that you can only use an object on the thread from which is was created or obtained, ivars shouldn't be accessed directly for any persisted properties, and that getters and setters for persisted properties cannot be overridden.
So to work with Realm, your model should look like this:
#interface Product : RLMObject
#property NSString *title;
#property NSString *thumbnailURL;
#property (nonatomic, strong) UIImage *thumbnail;
#end
#implementation Product
-(UIImage*)thumbnail
{
if (!_thumbnail) {
_thumbnail = [self loadImageFromCache];
}
return _thumbnail;
}
-(UIImage*)loadImageFromCache
{
// Load image from cache
return nil;
}
+(NSArray*)ignoredProperties
{
// Must ignore thumbnail because Realm can't persist UIImage properties
return #[#"thumbnail"];
}
#end
And usage of this model could look like this:
[[RLMRealm defaultRealm] transactionWithBlock:^{
// createInDefaultRealmWithObject: will populate object keypaths from NSDictionary keys and values
// i.e. title and thumbnailURL
[Product createInDefaultRealmWithObject:#{#"title": #"a", #"thumbnailURL": #"http://example.com/image.jpg"}];
}];
NSLog(#"first product's image: %#", [(Product *)[[Product allObjects] firstObject] thumbnail]);
Notice how initWithInfo isn't necessary because RLMObject already has initWithObject: and createInDefaultRealmWithObject: already do this.

Custom Object empty after creation

I have a custom object: Vendor that extends NSObject. I am initiating it like so:
NSDictionary *vendorObj = [vendors objectAtIndex:i];
Vendor *vendor = [[Vendor alloc] initWithVendorInfo:vendorObj];
NSLog(#"VendorObj: %#", vendorObj);
NSLog(#"Vendor: %#", vendor);
Here is what the class looks like:
#interface Vendor : NSObject
#property (nonatomic, copy) NSString *name;
#property (nonatomic, copy) NSString *description;
- (id)initWithVendorInfo:(NSDictionary *)vendorDetails;
#end
#implementation Vendor
- (id)initWithVendorInfo:(NSDictionary *)vendorDetails
{
self = [super init];
if(self)
{
_name = [vendorDetails[#"company_name"] copy];
_description = [vendorDetails[#"description"] copy];
}
return self;
}
If I NSLog vendorObj all the details are there. Once I initiate the Vendor object and NSLog it, the log shows:
2013-11-21 22:22:44.769 [48202:a07] Vendor:
I cannot seem to figure out why my object is nothing, no memory address, not even a null. What am I doing wrong here?
The problem is your description property. The NSObject class defines a description method. This method is called when you use a %# format specifier with an object.
Your description property is overriding that method.
Rename your description property to something else.

[MyClassName copyWithZone:]: unrecognized selector sent to instance?

I just implemented my class
#interface ExampleNestedTablesViewController ()
{
NSMutableArray *projectModelArray;
NSMutableDictionary *sectionContentDictionary;
}
- (void)viewDidLoad
{
[super viewDidLoad];
ProjectModel *project1 = [[ProjectModel alloc] init];
project1.projectName = #"Project 1";
ProjectModel *project2 = [[ProjectModel alloc] init];
project2.projectName = #"Project 2";
if (!projectModelArray)
{
projectModelArray = [NSMutableArray arrayWithObjects:project1, project2, nil];
}
if (!sectionContentDictionary)
{
sectionContentDictionary = [[NSMutableDictionary alloc] init];
NSMutableArray *array1 = [NSMutableArray arrayWithObjects:#"Task 1", #"Task 2", nil];
[sectionContentDictionary setValue:array1 forKey:[projectModelArray objectAtIndex:0]]; // **this line crashed**.
}
}
Here is my Project Model
#interface ProjectModel : NSObject
typedef enum
{
ProjectWorking = 0,
ProjectDelayed,
ProjectSuspended,
} ProjectStatus;
#property (nonatomic, assign) NSInteger idProject;
#property (nonatomic, strong) NSString* projectName;
#property (nonatomic, strong) NSMutableArray* listStaff;
#property (nonatomic, strong) NSTimer* projectTimer;
#property (nonatomic, assign) ProjectStatus projectStatus;
#property (nonatomic, strong) NSMutableArray* listTask;
#property (nonatomic, assign) NSInteger limitPurchase;
#property (nonatomic, strong) NSDate* limitTime;
#end
And the output is:
SDNestedTablesExample[1027:c07] -[ProjectModel copyWithZone:]: unrecognized selector sent to instance 0x7562920.
I didn't know which problem. Can you help me ?
Look at the docs for NSMutableDictionary setObject:forKey: (note you should use setObject:forKey:, not setValue:forKey:). Notice the expected type for the key. It must be of type id<NSCopying>. This means the key must conform to the NSCopying protocol.
Since your keys are of type ProjectModel, the error is complaining since your ProjectModel class doesn't implement the required method of the NSCopying protocol - copyWithZone:.
Are you sure you want to use a ProjectModel object as the key? Doing so also means you need a sane implementation of the isEqual: and hash methods, in addition to copyWithZone.
The solution is to update your ProjectModel class so it conforms to the NSCopying protocol and implements the copyWithZone: method. And also properly implement the isEqual: and hash methods. Or change the key to be just the idProject property (properly wrapped as an NSNumber).

Resources