Set NSDecimal to zero - ios

What are the different ways of setting a NSDecimal to zero? I'm not keen on any of the 3 I found so far.
NSDecimal zero = {0}; // Not obvious what's going on here.
NSDecimal zero = #(0).decimalValue; // #(0) appears to always return the same instance.
NSDecimal zero = [NSDecimalNumber zero].decimalValue; // [NSDecimalNumber zero] appears to always return the same instance.
Is there one that is most accepted than others? Am I missing some kind of NSDecimalZero constant/function?

I have never noticed that NSDecimal doesn't have a nice Create function.
I can't imagine another method than the 3 you list.
NSDecimal zero = {0};
You are right, this is not obvious, this is actually very far from obvious. Usual programmers won't look up the documentation to see what value the struct will represent with all attributes set to zero.
NSDecimal zero = #(0).decimalValue
I don't like it because it uses NSNumber and needlessly creates an autoreleased object.
NSDecimal zero = [NSDecimalNumber zero].decimalValue
This is my preferred solution. Using NSDecimal structs directly is done mostly for performance boosts (without creating objects on the heap). This method matches the intent because it uses a singleton constant.
However, if you have a lot of code involving NSDecimal and performance is really important for you, create your own function/macro to initialize the struct and use this function everywhere. Then this problem won't matter to you because the function name will make the code obvious.

NSDecimal is a C struct which you are not supposed to look inside (you can but you shouldn't) so that rules out the first which is technically looking inside the struct.
Either of the second two are absolutely fine. Note that, in C, assigning to a struct copies all the fields, so although [NSDecimalNumber zero] always returns the same object, your NSDecimal will be a unique struct and changing its contents won't affect any other NSDecimal that has been "created" in the same way.

I guess you need to use NSDecimalNumber,
Typically we do as:
NSDecimalNumber *zeroDecimal = [[NSDecimalNumber alloc] initWithFloat:0.f];
NSDecimal zero = #(0).decimalValue; // #(0) appears to always return
the same instance.
NSDecimal zero = [NSDecimalNumber zero].decimalValue; //
[NSDecimalNumber zero] appears to always return the same instance.
Above two returns equivalent value of 0.0, first one is just the shorthand notation for the second one. You boxed 0 to NSDecimalNumber, using new syntax.
However, NSDecimal is typedefStruct that looks like this
typedef struct {
signed int _exponent:8;
unsigned int _length:4; // length == 0 && isNegative -> NaN
unsigned int _isNegative:1;
unsigned int _isCompact:1;
unsigned int _reserved:18;
unsigned short _mantissa[NSDecimalMaxSize];
} NSDecimal;

Related

type casting in objective-c, (NSInteger) VS. integerValue

I don't very understand about the diference between (NSInteger)aNumberValue and [aNumberValue integerValue], then do some test. For example, here is a response data from server:
You can see it's an int but the value is hold by NSNumber. I retrieve the data by writting NSInteger count = (NSInteger) dic[#"count"];, and in Xcode debug area, saw this:
it's really a strange value but when I run po count and saw this:
anyway, the value is correct, but another strange thing is:
the number 2 is not less than 100!
Then I try NSInteger a = [dic[#"count"] integerValue] and saw the normal value in Xcode debug area:
and:
So, I am a little bit confused, what's the deference between (NSInteger)aNumberValue and [aNumberValue integerValue]?
NSNumber is a class; NSInteger is just a typedef of long, which is a primitive type.
dic[#"count"] is a pointer, which means that dic[#"count"] holds an address that points to the NSNumber instance. NSNumber has a method called integerValue which returns an NSInteger as the underlying value that the NSNumber instance represents. So you can conclude that [dic[#"count"] integerValue] gets you a long, and that's how you retrieve the value out of NSNumber.
You don't retrieve the value of NSNumber by casting it to NSInteger. That's because dic[#"count"], as I said, is a pointer. So by writing
NSInteger count = (NSInteger) dic[#"count"];
you are actually casting the pointer itself to an NSInteger, which has nothing to do with the actual represented value. The value 402008592 you see is just a decimal representation of the value of the pointer, which is an address.
The command po is used for printing objects, so lldb will actually try to print out the object at the address of count. That's why you get 2 back using po. You can try p count and you'll get 402008592.
About po count < 100: The expression (count < 100) is evaluated first; since count is really just an NSInteger of 402008592, it will evaluate to false.
The root issue is that Objective-C collection classes can only store Objective-C objects, not primitive types like float, int or NSInteger.
Therefore NSNumber provides a mechanism to store numbers and booleans in object form.
The value 402008592 looks like an address, so it's probably an NSNumber object containing an NSInteger value.
Don't get confused by the NS prefix of NSInteger and NSUInteger; they are still primitive types and not objects like NSNumber.

Difference between (BOOL) and boolValue in iOS

What is the difference between these two lines?
alertObj.AlertAddressed=[[NSNumber numberWithBool:sqlite3_column_int(compiledStatement, 9)] boolValue];
alertObj.AlertAddressed=(BOOL)[NSNumber numberWithBool:sqlite3_column_int(compiledStatement, 9)];
I'm getting a different result for these two lines - why?
Thanks in advance.
First one gives you actual bool value.
Second one type cast to BOOL the result of
[NSNumber numberWithBool:sqlite3_column_int(compiledStatement, 9)]
I don't know how good you are at pointers but I try to explain
First of all when you get an NSNumber it is an object, and the value of an object is at first it's pointer (so something like 0x0000af) this is simple an adress in the memory, and this address contains your NSNUmber wich contains the actual value (so let's say a bool information in your example)
It's pretty simple, when you do
(BOOL)alertObj.AlertAddressed=(BOOL)[NSNumber numberWithBool:sqlite3_column_int(compiledStatement, 9)];
what actually happen is the try to cast the 0x0000af part to a bool value... NOT what NSNumber contains (what you actually get depends on the current Pointer of the object when you try this)
alertObj.AlertAddressed=[[NSNumber numberWithBool:sqlite3_column_int(compiledStatement, 9)] boolValue];
this is something actually implemented in NSNumber and therefore it completly respects what the object does and gives you the bool saved in your NSNumber, and not a cast from it's pointer
NSNumber is an object, BOOL is a primitive type.
NSNumber is a class that wraps numbers, but you can't use to make operations, if you want you should unwrap calling a specific method. Since NSNumber is an object your variable is a pointer holding a reference to an object, not a value.
The first line is correct, the second is wrong because you are casting a pointer to a bool type.
alertObj.AlertAddressed=[[NSNumber numberWithBool:sqlite3_column_int(compiledStatement, 9)] boolValue]; This will convert you value to BOOL
alertObj.AlertAddressed=(BOOL)[NSNumber numberWithBool:sqlite3_column_int(compiledStatement, 9)];This is like casting. Considers [NSNumber numberWithBool:sqlite3_column_int(compiledStatement, 9)] will return bool value.

Performing arithmetic on double

I have an app whose purpose is to compare chronologically ordered time intervals, which are stored by Core Data (via MagicalRecord) as attributes of type double, on an entity called TimedActivity. Ordering directions are supplied by attributes called activityOfInterest and benchmarkActivity on another entity named SearchSpecs. The scheme may seem a bit overcomplicated since I'm pretty green, but that part of it works.
The problem is that getting percentages from two doubles appears to be a bit of a runaround, at least according to the research I've done. I don't need extreme precision. Round seconds are fine. I found a suggestion relating to the use of NSDecimalNumber, but it too seemed like a long way around the corner.
Here is the relevant code in it's current state, with pseudocode to indicate my problem area:
#pragma mark - Go button case handlers
-(void) handleAvsAAction
{
// NSArray *searchSpecsObjects = [SearchSpecs MR_findAll];
// NSLog(#"SearchSpecs number of objects is %i",[searchSpecsObjects count]);
NSArray *searchSpecsArray = [SearchSpecs MR_findAll];
NSLog(#"searchSpecsArray count is %i", [searchSpecsArray count]);
SearchSpecs *thisSpec = [searchSpecsArray objectAtIndex:0];
NSLog(#"SearchSpec activityOfInterest should be %#", thisSpec.activityOfInterest);
NSLog(#"SearchSpec benchmarkActivity should be %#", thisSpec.benchmarkActivity);
// NSArray *activityOfInterestArray;
// NSArray *benchmarkActivityArray;
NSNumber *activityOfInterestDurationTotal;
NSNumber *benchmarkActivityDurationTotal;
NSPredicate *activityOfInterestPredicate = [NSPredicate predicateWithFormat:#"name == '%#'",thisSpec.activityOfInterest];
NSPredicate *benchmarkActivityPredicate = [NSPredicate predicateWithFormat:#"name == '%#'", thisSpec.benchmarkActivity];
activityOfInterestDurationTotal = [TimedActivity MR_aggregateOperation:#"sum:" onAttribute:#"duration" withPredicate:activityOfInterestPredicate];
NSLog(#"The sum of all the durations for the activity of interest is %zd", activityOfInterestDurationTotal);
benchmarkActivityDurationTotal = [TimedActivity MR_aggregateOperation:#"sum:" onAttribute:#"duration" withPredicate:benchmarkActivityPredicate];
NSLog(#"The sum of all the durations for the benchmark activity is %zd", benchmarkActivityDurationTotal);
[self doTheMathAvsA];
}
-(void) doTheMathAvsA
{
// Get the total and respective percentages of the totalled durations from the criteria distilled in handleAvsAAction
NSNumber *total;
total = (activityOfInterestDurationTotal + benchmarkActivityDurationTotal);
}
Edit: modified doTheMathAvsA to clarify the desired result.
All help or suggestions appreciated!
Second edit:
OK, your answer below makes sense, and thanks #Martin R!
However, the two quantities in question here originate as NSTimeIntervals, and as mentioned above, are stored as attributes of type double, on an entity called TimedActivity.
So, it seemed rational to me to slightly rewrite the code to extract them from the persistent store as NSTimeIntervals, which I am assured are really just doubles. However, when I do this, I get this error:
Assigning to 'NSTimeInterval' (aka 'double') from incompatible type 'NSNumber *'
Here are the modified declarations:
NSTimeInterval activityOfInterestDurationTotal;
NSTimeInterval benchmarkActivityDurationTotal;
And here's where the error appears:
activityOfInterestDurationTotal = [TimedActivity MR_aggregateOperation:#"sum:" onAttribute:#"duration" withPredicate:activityOfInterestPredicate];
NSLog(#"The sum of all the durations for the activity of interest is %#", activityOfInterestDurationTotal);
benchmarkActivityDurationTotal = [TimedActivity MR_aggregateOperation:#"sum:" onAttribute:#"duration" withPredicate:benchmarkActivityPredicate];
NSLog(#"The sum of all the durations for the benchmark activity is %#", benchmarkActivityDurationTotal);
OK, I assume that the NSNumber referred to in the error message is this property in the TimedActivity managed object subclass, auto-generated from the data model:
#property (nonatomic, retain) NSNumber * duration;
So my question becomes:
Is it really necessary to resort to such seemingly ever-widening circles of conversion and retro-conversion to perform such a seemingly simple calculation? Or am I missing a more straightforward solution?
Thanks!
You cannot perform arithmetic directly on NSNumber objects. The easiest solution is
to convert them to double for the addition:
double tmp = [activityOfInterestDurationTotal doubleValue] + [benchmarkActivityDurationTotal doubleValue];
and the result back to NSNumber, if necessary:
NSNumber *total = #(tmp);
Update: By default, the Xcode generated accessor methods use Objective-C objects even
for primitive Core Data types such as "Double". You can change that by selecting the
"Use scalar properties for primitive data types" option when creating the subclass files.
Then a "Double" property is declared as
#property (nonatomic) double activityOfInterestDurationTotal;
and you can access it "directly" as for example
NSTimeInterval duration = thisActivity.duration;
because NSTimeInterval is just another name for double.
But there is another problem: The MagicalRecord "convenience method" MR_aggregateOperation: uses a special fetch request with NSDictionaryResultType to
fetch the sum of all duration values. And even if you chose to use a scalar property
for the duration, the result of MR_aggregateOperation: is always some Objective-C object, in this case NSNumber, there is no way around it.
So the only way to avoid a conversion between NSNumber and double would be to use a scalar
property as described above, and instead of using MR_aggregateOperation:, fetch all
objects and add the duration values yourself in a simple loop.
But note that the fetch request with the aggregate operation performs the calculations
on the SQLite level, this is probably more effective then actually fetching all objects.

Nested NSArray filtering

I have the need to obtain the maximum value of a property of a collection of custom objects of the same class. The objects are stored in a NSArray, and the property happens to be another NSArray of numbers.
Let me explain in detail:
NSArray *samples; // of CMData, 4000 elements
CMData is a class that models a sample, for a specific moment in time, of a set of different channels that can have different values.
#interface CMData : NSObject
#property (nonatomic) NSUInteger timeStamp;
#property (nonatomic, strong) NSArray *analogChannelData; // of NSNumber, 128 elements
#end
(I have stripped other properties of the class not relevant to the question)
So for example, sample[1970] could be:
sample.timeStamp = 970800
sample.analogChannelData = <NSArray>
[
[0] = #(153.27)
[1] = #(345.35)
[2] = #(701.02)
...
[127] = #(-234.45)
]
Where each element [i] in the analogChannelData represents the value of that specific channel i for the timeStamp 970800
Now I want to obtain the maximum value for all the 4000 samples for channel 31. I use the following code:
NSUInteger channelIndex = 31;
NSMutableArray *values = [[NSMutableArray alloc] init]; // of NSNumber
// iterate the array of samples and for each one obtain the value for a
// specific channel and store the value in a new array
for (CMData *sample in samples) {
[values addObject:sample.analogChannelData[channelIndex]];
}
// the maximum
NSNumber *maxValue = [values valueForKeyPath:#"#max.self"];
I want to replace this programming structure by a filter through an NSPredcicate or use valueForKeyPath: to obtain the maximum of the data I need.
Anyone knows how to do this without a for loop? Just using NSPredicates and/or valueForKeyPath?
Thank you very much in advance for your help.
Update 1
Finally I benckmarked the for-loop version against the keyPath version (see accepted answer) and it runs much faster so it is better to go with a for loop.
Recalling some lessons from my algorithms classes, I implemented an even faster version that doesn't need an array to store the values. I just iterate over the selected channel and just choose the maximum in each iteration. This is by far the fastest version.
So:
version 1: for loop (see code above)
version 2: version with custom property (see selected answer from Marcus, update 2)
version 3: new code
Code for version 3:
NSUInteger channelIndex = 31;
NSNumber *maxValue = #(-INFINITY);
for (CMTData *sample in samples) {
NSNumber *value = sample.analogChannelData[channelIndex];
if (value) { // I allow the possibility of NSNull values in the NSArray
if ([value compare:maxValue] == NSOrderedDescending)
maxValue = value;
}
}
// the maximum is in maxValue at the end of the loop
Performance:
After 20.000 iterations in iOS simulator:
Version 1: 12.2722 sec.
Version 2: 21.0149 sec.
Version 3: 5.6501 sec.
The decision is clear. I'll use the third version.
Update 2
After some more research, it is clear to me now that KVC does not work for infividual elements in the inner array. See the following links: KVC with NSArrays of NSArrays and Collection Accessor Patterns for To-Many Properties
Anyway because I wanted to compute the maximum of the elements it is better to iterate the array than use some tricks to make KVC work.
You can solve this with using Key Value Coding and the collection operators.
NSNumber *result = [sample valueForKeyPath:#"#max.analogDataChannel"];
Update 1
As Arcanfel mentioned, you can join the arrays together:
NSNumber *result = [samples valueForKeyPath:#"#max.#unionOfArrays.#analogChannelData"];
I would suggest reading the documentation that we both linked to. There are some very powerful features in there.
Update 2
Further to HRD's answer, he has your solution, you need to combine his changes with KVC.
Add a propert to your CMData object for currentChannel. Then you can call
[samples setValue:#(channelIndex) forKey:#"currentChannel"];
Which will set it in every instance in the array. Then call:
[samples valueForKeyPath:#"#max.analogDataForCurrentChannel"];
Then you are done.
I have not tested out the code yet, but I think this is exactly what you are looking for:
[samples valueForKeyPath:#"#max.(#unionOfArrays.analogChannelData)"];
I guess you can also use #distinctUnionOfArray to remove duplicate values.
Here is the link to Apple Documentation that covers collection operators.
Hope this is helpful!
Cheers!
A suggestion for further exploration only
Offhand it is not clear you can do this as-is with a single KVC operator. What you might consider is adding two properties to your class: currentChannel, which sets/gets the current channel; and analogChannelDataForCurrentChannel, which is equivalent to analogChannelData[currentChannel]. Then you can:
samples.currentChannel = channelIndex;
... [samples valueForKeyPath:"#max.analogChannelDataForCurrentChannel"];
with any appropriate locking between the two calls if thread-safety is required (so one thread does not set currentChannel, then a second, and then the first do the KVC operator with the second's channel...).
HTH

Allocating a NSUInteger IndexBuffer

I am trying to retrieve my NSIndexSet by calling -getIndexes:maxCount:indexRange
Here is my code
const NSUInteger arrayCount = picturesArray.count;
NSUInteger theIndexBuffer[arrayCount];
[picturesArray getIndexes:theIndexBuffer maxCount:arrayCount inIndexRange:nil];
However, in the debugger the IndexBuffer is always showing as -1. When I initialize it with a static number like NSUInteger theIndexBuffer[10], I get a proper instance.
This is probably because it doesnt know what arrayCount is at compile time.
What is the correct way of doing this?
You can dynamically allocate it using a pointer like this:
NSUInteger *theIndexBuffer = (NSUInteger *)calloc(picturesArray.count, sizeof(NSUInteger));
// Use your array however you were going to use it before
free(theIndexBuffer); // make sure you free the allocation
In C, even though this is a dynamically allocated buffer, you can use the array subscript operators and (for the most part) pretend that it's just an array. So, if you wanted to get the third element, you could write:
NSUInteger thirdElement = theIndexBuffer[2]; // arrays are 0-indexed
Just don't forget to free it when you're done.
I don't think you did anything wrong. It's valid in C99. You can double check by seeing if this evaluates as true:
sizeof(theIndexBuffer) == arrayCount * sizeof(NSUInteger)

Resources