iOS5 Core Data and NSNumber is there autoboxing/unboxing? - ios

Coming from Java, I'm pretty used to autoboxing, where an int is automatically wrapped to an Integer when needed, and an Integer may be unboxed into a primitive. Is there something similar that I can rely upon in iOS5?
currently, I'm using core data, and it takes a lot of typing to keep having to type
number.intValue
//or
number.boolValue
is there some way to use an NSNumber directly in equations and such? for example:
int x = 5+ nsNumberInstance;
Furthermore, every time I need to re-assign a number in the core data, I'm creating a new object like this.
managedObject.dynamicProperty = [NSNumber numberWithInt: int];
is there a better way to change the value of an already created NSNumber? What kinds of nifty shortcuts may I use to save myself from carpal tunnel 10 years from now?
Thank you!

Actually, when you are in your data model, and you use the "Create NSManagedObject subclass" menu item, there is an option that you can select titled "Use scalar properties for primitive data types".
This automatically handles this for you in many cases.
Here are some examples:
BOOL:
#property (nonatomic, retain) NSNumber * aBool;
becomes
#property (nonatomic) BOOL aBool;
NSDate:
#property (nonatomic, retain) NSDate * aDate;
becomes
#property (nonatomic) NSTimeInterval aDate;
Integer 32:
#property (nonatomic, retain) NSNumber * aNumber;
becomes
#property (nonatomic) int32_t aNumber;
and
Float:
#property (nonatomic, retain) NSNumber * aFloat;
becomes
#property (nonatomic) float aFloat;
NSDecimalNumber and NSString stay the same.
You can change these yourself in the previously generated header file if you have already generated the subclasses and the accessor methods will automatically update without having to re-generate the subclass.

Outside of Cocoa bindings, I can't think of many other places that have autoboxing of scalar types in Cocoa or Cocoa touch, so unfortunately you're out of luck there.
You don't really gain anything by working with NSNumbers in calculations, so dealing with the objects there isn't really necessary. It's much easier to work with scalar types, and then convert back and forth between NSNumbers when storing these numbers in Core Data, arrays, etc. The one case where you'd want to stay in this form would be NSDecimalNumbers, which do not represent numbers as your standard floating point values, and thus avoid the glitches you see when trying to work with decimals in those types.
Core Data stores objects, so you're not going to get around that at a base level, but you can make your life a little easier by using custom accessors on your NSManagedObject subclasses that take and return scalar values. Apple has an example of this in the "Managed Object Accessor Methods" section of the Core Data Programming Guide, where they show how to set up an accessor for a CGFloat value, instead of using an NSNumber:
#interface Circle : NSManagedObject
{
CGFloat radius;
}
#property CGFloat radius;
#end
#implementation Circle
- (CGFloat)radius
{
[self willAccessValueForKey:#"radius"];
float f = radius;
[self didAccessValueForKey:#"radius"];
return f;
}
- (void)setRadius:(CGFloat)newRadius
{
[self willChangeValueForKey:#"radius"];
radius = newRadius;
[self didChangeValueForKey:#"radius"];
}
#end
As a side note, using the dot syntax for -intValue and -boolValue, while it works, is not recommended. These are not properties, but one-way methods that extract values from the NSNumbers. Use brackets when dealing with them to make this clear in your code.

Related

Why is my ivar not getting set on NSManagedObject Subclass

I have a project using CoreData. I use Mogenerator to generate the subclasses.
When I set the value of a property, this value isn't actually assigned. Each subsequent time I try to set the value, the previous value I set it to was not assigned.
This worked fine as my underlying data framework was Mantle, but since moving to CoreData, this stopped working. I rely on KVO to keep some UIView objects up-to-date with the model.
Again, the ivars of a CoreData NSManagedObject subclass do not seem to take the values I assign them.
Consider the following interface:
#interface Light : _Light{}
/**
Light / Color Properties
*/
#property (nonatomic, assign) CGFloat brightness; // 0...1
#property (nonatomic, assign) CGFloat hue; // 0...1
#property (nonatomic, assign) CGFloat saturation; // 0...1
#property (nonatomic, assign, getter = isEnabled) BOOL enabled;
#property (nonatomic, readonly) UIColor *color; // derived from the above
- (void)setHue:(CGFloat)hue saturation:(CGFloat)saturation; // it often makes sense to set these together to generate fewer KVO on the color property.
#end
and the following .m file:
#interface Light ()
{
CGFloat _hue, _saturation, _brightness;
UIColor *_color;
}
#property (nonatomic, assign) BOOL suppressColorKVO;
#property (nonatomic, readwrite) UIColor *color;
#end
#implementation Light
#synthesize suppressColorKVO = _suppressColorKVO;
- (void)setHue:(CGFloat)hue saturation:(CGFloat)saturation
{
BOOL dirty = NO;
if (saturation != _saturation) {
// clamp its value
[self willChangeValueForKey:#"saturation"];
_saturation = MIN(MAX(saturation, 0.0f), 1.0f);
[self didChangeValueForKey:#"saturation"];
dirty = YES;
}
if (hue != _hue) {
[self willChangeValueForKey:#"hue"];
_hue = MIN(MAX(hue, 0.0f), 1.0f);
[self didChangeValueForKey:#"hue"];
dirty = YES;
}
if (dirty) {
if (!_suppressColorKVO) {
[self setColor: self.color];
}
}
}
// other stuff... the color accessors are also custom. Derived from the h, s, b values.
#end
I assume I'm not playing nice with CoreData, but I have no idea what's wrong. These hue, saturation, brightness are all 'transient' (not in the core data sense) because they are constantly updated by some hardware we are interfacing with so there's no need to save their state.
If hue and saturation are properties in your model then you should be setting their values using setPrimitiveValue:forKey: (or the associated generated primitive methods).
That said, your code all looks custom as model attributes would be NSNumber instances and mogenerator would create value methods for you. So I'm going to guess that these attributes you have aren't backed in the model and that's why they aren't being stored.
So, add the attributes to the model and access the values using the appropriate methods.
In the end it had nothing to do with CoreData. This approach above DOES work with CoreData objects. You can have in a subclass some "transient" properties that exist outside of the CoreData NSManagedObject and you can create your own ivars for them, and your own accessors, and it cooperates.
In relation to this question, I have a complex system that also sends some commands to some hardware, and the hardware returns a response whether it accepted the command with the current status. It turns out I had a bug in that handler which was setting these values back to some unexpected value.
What helped me debug it were using watchpoints in the debugger. Really handy feature! You set a watchpoint and it will break in the debugger whenever the memory address of your variable is set with a new value. (A tiny bit more on that here)

Best iOS data structure to store sizes and colours of a product

I am developing an iOS application that deals with products. These products obviously can have sizes and colours (clothes, for example).
Now I need a good data structure to store the available colours and sizes for the current product (for one product at a time). The price has also to be a part of the data structure, since every colour-size combination might have a different price, as well as a URL for the product image of the specified size.
I have thought of a two-dimensional array (i.e. NSArrays of NSArray) with first dimension as colour and second as the size and the content of the cell is the price and the URL, but then there is some inconvenience when the product has only sizes without colours or vice versa.
Is there some other better data structure that satisfies my needs, or my choice was the best?
Thanks!
You should build your own data structure(s) that have layers. For example:
#interface Variant : NSObject
#property (nonatomic, strong) UIColor *color;
#property (nonatomic) CGFloat price;
#property (nonatomic, strong) NSString *size; // might want a better structure to hold this
#end
#interface Product : NSObject
#property (nonatomic, strong) NSString *title;
#property (nonatomic, strong) NSArray *variants; // Is an array of Variant's
#end
If you simply nest arrays into arrays you the structure and benefits of object oriented programming.

Declaring floats in objective c

I'm new to Objective-C and I'm having trouble with the whole nonatomic, strong, weak, etc. I'm wondering if I will have any issues using Core Data with float values which are defined like so:
#property (nonatomic) float * rating;
#property (nonatomic) float * mRating;
Should I declare the differently?
Yes, you should declare them without asterisks:
#property (nonatomic) float rating;
#property (nonatomic) float mRating;
Asterisks indicate pointers. All Objective C classes are declared with asterisks, because instances are referred to through pointers. Primitives such as floats, ints, etc. are defined as values, i.e. without asterisks. Same goes for typedef-ed types such as CGFloat and NSInteger: scalar fields of these types should be defined without an asterisk.
You should definitely lose the *, unless you are meaning to create a pointer. Outside of that it looks great!

C-array as property in iOS

I am programming for iOS, and using ARC.
I am trying to use a c-array as property, but it reports error.
#property (strong, nonatomic)NSString *mappingTable[70][254];
The error is "Property cannot have array or function type NSString *[70][254]". How can I solve this problem? How can I declare c-array as property?
Note:
This is a two dimensional array, I think it is much easier to just use c-array, so I didn't use NSArray for it.
Surprised this hasn't been suggested already but you can store the c-array in an NSData object. I just used this method to store an array of frames.
#property (nonatomic) NSData *framesArray;
// Create and initialize your c-style frames array
CGRect frames[numberOfFrames];
...
self.framesArray = [NSData dataWithBytes:frames length:(sizeof(CGRect) * numberOfFrames)];
// To Access the property
NSUInteger arraySize = [self.framesArray length] / sizeof(CGRect);
CGRect *frames = (CGRect *) [self.framesArray bytes];
You can't declare it in that format. As the error message states you can't use C-style arrays in property declarations.
The new shorter syntax for arrays makes NSArray and NSMutableArray less of a pain. Instead of
[array objectAtIndex:3]
you can simply use
array[3]
I think in the long run the benefit of using Objective-C objects will outweigh the comfort of using C-style arrays.
you can not declare c/c++ arrays as properties, you could either use objective-c NSArray/NSMutableArray for property or you could declare c++ array.
#property (strong,nonatomic)NSArray *mappingTable;
or declare pure c style character array like this
char mappingTable[70][224];
If you are only going to use it as a private property of the class. Then keep it simple.
skip the YourClass.h file. And write it directly in the YourClass.m file like this.
//YourClass.m file
#import "YourClass.h"
#interface YourClass()
#property (strong,nonatomic)NSArray *mappingTable;
#end
#implementation YourClass
#synthesize mappingTable;
#end

Core Data: implementing property that is dependent on other

I have following situation in my project (in which I use Core Data): I have an entity which has two BOOL properties: isCompleted and isNonVisit. It also has third property: NSNumber *status - the value of the property depends on both isCompleted and isNonVisit values.
When either of the BOOL property changes, I want status property to be actualised automatically.
All three properties must be present in underlying database, since I use fetchedResultsController that makes use of status property (as sort descriptor and as sectionNameKeyPath).
I came up with following solution:
in .h file:
#property (nonatomic, retain) NSNumber *isCompleted;
#property (nonatomic, retain) NSNumber *isNonVisit;
#property (nonatomic, retain) NSNumber *status;
- (NSNumber *)calculateStatus; //Returns proper status value based on isCompleted and nonVisit property values.
in .m file:
#dynamic isCompleted;
#dynamic isNonVisit;
#dynamic status;
- (void)setIsCompleted:(NSNumber *)newValue
{
[self willChangeValueForKey:#"isCompleted"];
[self setPrimitiveValue:newValue forKey:#"isCompleted"];
[self didChangeValueForKey:#"isCompleted"];
self.status = [self calculateStatus];
}
- (void)setIsNonVisit:(NSNumber *)newValue
{
[self willChangeValueForKey:#"isNonVisit"];
[self setPrimitiveValue:newValue forKey:#"isNonVisit"];
[self didChangeValueForKey:#"isNonVisit"];
self.status = [self calculateStatus];
}
The solution seems to work.
So, my question is: Is it OK? Am I violating some rules of CoreData or KVO?
Thanks for any suggestions.
Your method seems sound.
The only suggestion I would have is to reduce the redundancy by extracting the boolean information from the status with accessor methods rather than storing them. You still should be able to use the desired predicates for your fetch requests just using the status variable. But the overhead of storing this extra information should be minimal.

Resources