Keeping Swift Double precision in Objective C - objective-c

A double created in Swift
let d: Double = 1.0
when passed to Objective C, will not preserve the .0. It ends up as 1.
Is there a way preserve .0 for whole doubles in Objective C?
Edit:
Here's what I'm doing:
Parent.m
#implementation Parent
-(void)log:(NSDictionary*)data {
}
#end
Parent.h
#interface Parent : NSObject
-(void)log:(NSDictionary*)data;
#end
Child.swift
class Child: Parent {
func log() {
let measure = Double(1)
let isLoggedIn = false
let data: [String: Any] = ["is_logged_in": isLoggedIn, "measure": measure]
log(data) // calling parent method, measure ends up as 1
}
}

From the wording of your question you might need to research the difference between a double value (the same in both languages) and a textual representation of a double value (which your question suggests might not default to the same in both languages).
Once you are clear on that look up the NSString method stringWithFormat and see if you can produce the format you require using that. (NSLog() supports the same formatting.)
If the above fails to meet your requirements look up NSNumberFormatter.
HTH

Related

Expressing enum with associated values in Objective-C

In Swift there are enums with associated values:
enum Coffee {
case Black
case BlackWithSugar(spoons: Int)
// ....
}
Clearly the goal here is to:
Have one case that expresses BlackWithSugar (not 100 cases, like BlackWith1Sugar, BlackWith2Sugar) and so on
But preserve additional info (number of spoons) inside the same structure
What's the closest / most elegant way to express the same in Objective-C?
Note: I saw this question, but 2 answers do not say how to express the same intent in Objective-C. I'm ok with using something other than enum, and using Swift is not an option.
While it is possible with a lot of work to accomplish something very similar to Swift's enums with associated types in Objective-C (see the blog post I linked in a comment above), it requires a bunch of hard-to-comprehend code.
I'd recommend taking a more natural Objective-C style approach. You'll lose out on some of the type safety Swift provides, but ObjC is naturally a less type-safe language.
For example:
// Create an options enum. Bridges into Swift as an OptionSet
typedef NS_OPTIONS(NSInteger, CoffeeOptions) {
CoffeeOptionsBlack = 0,
CoffeeOptionsWithSugar = 1 << 0,
CoffeeOptionsWithCream = 1 << 1
};
// Create a (non-extensible) string-typed "enum". Bridges into Swift as an enum-style struct with string "raw values"
typedef NSString *CoffeeQuantityKey NS_TYPED_EXTENSIBLE_ENUM;
static CoffeeQuantityKey const CoffeeQuantityKeySpoonsOfSugar = #"SpoonsOfSugar";
static CoffeeQuantityKey const CoffeeQuantityKeyTeaspoonsOfCream = #"TeaspoonsOfCream";
#interface CoffeeMachine : NSObject
- (void)makeCoffeeWithOptions:(CoffeeOptions)options quantities:(NSDictionary<CoffeeQuantityKey, NSNumber *> *)quantities;
#end
#implementation CoffeeMachine
- (void)makeCoffeeWithOptions:(CoffeeOptions)options quantities:(NSDictionary<CoffeeQuantityKey, NSNumber *> *)quantities
{
// Make coffee
if (options & CoffeeOptionsWithSugar) {
NSNumber *sugarAmount = quantities[CoffeeQuantityKeySpoonsOfSugar] ?: #1; // Default to 1 spoon
NSLog(#"Adding %# spoons of sugar", sugarAmount);
}
if (options & CoffeeOptionsWithCream) {
NSNumber *creamAmount = quantities[CoffeeQuantityKeyTeaspoonsOfCream] ?: #1; // Default to 1 teaspoon
NSLog(#"Adding %# teaspoons of cream", creamAmount);
}
}
#end
This also has the advantage of bridging relatively nicely into Swift:
let cm = CoffeeMachine()
cm.makeCoffee(options: [.withSugar, .withCream], quantities: [.spoonsOfSugar : 3])

Creating a private 2D float array - Objective C

I am tring to create a private 2D float array and initialize it in constructor. I am getting "Expected Expression" error. I searched for a long while and couldn't find anything.
Here is my code:
#interface SampleClass : NSObject{
#private
float stops[2][2];
}
#end
#implementation SampleClass
- (id) init{
self = [super init]; // Edited
stops = { {1.0, 1.0}, {1.0, 2.0} }; // It gives "Expected Expression" at this line
return self;
}
#end
I tried different versions like:
stops = { {1.0, 1.0}, {1.0, 2.0} };
stops = { 1.0, 1.0, 1.0, 2.0 };
stops[][] = { {1.0, 1.0}, {1.0, 2.0} };
Non of them seems to work.
I am new to Objective C so any recommendation is appreciated.
(Objective-)C does not support assignment of one array to another, there are workarounds involving struct as they are assignable but you don't need to go there.
If you are after a constant array to be used by instances you can just declare it as static:
static const float stops[2][2] = { {27.3, 51.7}, {93.2, 42.24}};
The static makes stops accessible only to code within the same file. You can place the declaration between the #implementation and #end to at least visually associate it as belonging to a class.
The above is not suitable if you need a variable array, but does form part of a solution. Keep your instance variable:
#private
float stops[2][2];
This must be an array, not some pointer, as it must allocate the space for your floats. Next use the above declaration but give it a different name:
static const float _stops_init[2][2] = { {27.3, 51.7}, {93.2, 42.24}};
and then in your init use the standard C function memcpy() to copy the values in the memory occupied by _stops_init into the memory occupied by stops:
memcpy(stops, _stops_init, sizeof(_stops_init));
Here sizeof() will return the total size in bytes of the memory used by your float array _stops_init and memcpy() copies those bytes over those associated with stops – that is it implements array assignment which C doesn't directly support.
Using the static const array rather than a local variable define in init() as the source of your values saves re-creating the source on every call to init().
The above code doesn't do all the checks it should - at minimum an assert() checking that the sizes of stops and _stops_init are the same is advisable.
HTH

How should I write a property declaration for C array in ObjC?

I currently have this code:
#interface Matrix4 : NSObject
{
float mat[16];
}
#property (readonly) float mat[1];
I want the property to either give me the mat array or have multiple properties giving me readonly access to mat[1], mat[2], etc.
I current have "Property cannot have array of function type float[1]" as an error message
Arrays cannot be return values, so the property cannot have an array type. Instead you must return a pointer, so declare the property as a pointer to the element type of the array:
#property (readonly) float *mat;
Keep the instance variable as float mat[16] as you have now. Then implement the accessor to return a pointer to the array:
- (float *)mat {
return mat; // array decays to pointer automatically
}
Alternatively, you could have an accessor directly for the individual elements:
- (float)matIndex:(NSUInteger)i {
// maybe check bounds here?
return mat[i];
}
The problem with these approaches is that the information about the size of the array is lost, so you would probably want to put the size of the array in a macro or const variable. If you need something a bit more object-oriented, make the array an NSArray and store NSNumbers in it.
edit: One option would also be to wrap the array in a struct to preserve the size info, though you still probably want to pass it around by reference:
struct matrixf16 {
float f[16];
};
#interface Matrix4 : NSObject {
struct matrixf16 mat;
}
#property (readonly) struct matrixf16 *mat;
(Also, if I'm guessing correctly that the size is 16 because it's meant to hold a 4×4 matrix, why not make the array float f[4][4].)
As the compiler is telling you, properties cannot have array or function type.
You can manually implement the getter, like
#interface Matrix4 : NSObject {
float mat[16];
}
- (float *)mat;
#implementation
- (float *)mat {
return mat;
}
or you can consider using an NSArray instead, depending on your requirements. NSArray is definitely more overweight than a native C array, but it allows you to use properties.
However I suspect you have a design issue: it looks like you are trying to implement a squared matrix, but you are exposing the internal representation, most likely so that the client can set the matrix elements.
You should instead hide the internal representation and only expose methods to perform matrix operations. For instance, you can think of exposing a method which sets the matrix value, as:
- (void)setValue:(float)value forRow:(int)row column:(int)col {
NSParameterAssert(row >= 0 && row < 4 && col >= 0 && col < 4)
mat[row * 4 + col] = value;
}
and one that gives you an element back
- (float)valueForRow:(int)row column:(int)col {
NSParameterAssert(row >= 0 && row < 4 && col >= 0 && col < 4)
return mat[row * 4 + col];
}
and make the mat ivar private. This gives you also the flexibility of changing the internal representation at will, without breaking the client's code.
The above implementation is also very easy to generalize to a squared matrix of size, by providing a dimension parameter and using a NSArray or dynamic memory allocation (since variable-length arrays cannot be ivars).

Good practice for downcasting return type of inherited functions

I have got a Matrix-Class from which a Vector-Class is derived from and for extra functionality and better usage I've got a Vector3-Class which is derived from the Vector class. My problem is now that the Vector-class implements a function for instance +normalizeVector: which returns a new allocated Vector-instance. The subclass Vector3 should inherit these two functions but an inheritance leads to the function-prototypes that return a Vector-instance and not a Vector3-instance. This is just how inheritance works but is there a good practice how to solve that problem? A naive solution is to create Vector3 als a new class which subclasses NSObject but I want that Vector- and Vector3-instances can interact easily.
Here an code-example:
#interface Vector : NSObject {
....
}
+(Vector*) normalizeVector:(Vector*)v; //returns a new allocated Vector-instance
-(Vector*) normalize; //normalizes itself and returns itself
-(Vector*) otherFunction;
#end
#interface Vector3 : Vector {
}
-(Vector3*) specialFunction;
#end
usage of that code:
Vector3 *v3 = ...;
[[v3 normalize] specialFunction]; //Compiler gives me a warning because Vector has no specialFunction. Cast would help
[[Vector3 normalizeVector:v3] specialFunction]; //Compiler gives me a warning and during runtime it will crash because a `Vector` doesn't implement specialFunction
a cast to Vector3 would help but is not nice to work with and that also fails with the static function +normalizeVector: because in that static function a Vector-instance is allocated and a pointer-cast doesn't help.
any ideas? or other approaches / other modeling ?
edit: Code for my static function normalizeVector which gets inherited by Vector3:
#implementation Vector
...
+(Vector*) normalizeVector:(Vector *)v
{
unsigned int dim = vector_max(v.cols, v.rows);
Vector *res = [[[Vector alloc]initAsColumnVectorWithDim:dim] autorelease];
[Vector normalizeVector:v destination:res]; // this does only the logic: calc length and divide each component by the len and store at the vector passed to destination
return res;
}
#end
You will notice that -init methods always return type id -(id)init {..} exactly becauase of this.
Also, instead of [Vector alloc] - as you have noticed you don't actually know what Class you are in at runtime (it could be a subclass), so instead just use [self alloc] where self is the current Class because you are in a Class method. So, if you do [Vector3 normalizeVector:v] self is Vector3 and if you do [Vector normalizeVector:v] self is Vector.
Try adjusting your +normailzeVector: method to
+ (id)normalizeVector:(Vector *)v {
unsigned int dim = vector_max(v.cols, v.rows);
id res = [[[self alloc] initAsColumnVectorWithDim:dim] autorelease];
[self normalizeVector:v destination:res];
return res;
}
Just a note, + (id)normalizeVector: is not a function and definitely not a static function. It is a class method, it just helps to get the terms right.
In this case I would make normaliseVector an instance method. So instead of
Vector *newV = [Vector normalizeVector:v];
call
Vector *newV = [v normalizeVector];
Then you can produce a different normalizeVector for Vector and Vector3
EDIT:
For [[v3 normalize] specialFunction]; there is a problem in that normalize can sometimes return an object that specialFunction does not work on - ie it only works if v3 is a Vector3. So in this case there is extra information you have so a cast would be needed or that Vector3 normailze differs from Vector's. In this case I would produce a cover method on Vector3 to call normalize] specialFunction] so that the cast is in Vector3 specific code.

How to sort an NSArray where 1 value is dec and 1 value is float

My current project does a great deal of aggregation and one of the values I wanted to sort on is coming back in 2 flavors
My first source will return 0.9 / 1 / 1.1
My second source will return 2.349823432 / 4.93432343
My question is 2 fold
What type should I set on my object
to capture this value so sorting
works correctly. I'm asking because
I currently parse json and set these
values manually.
After the value is
set what is the best way to sort w/
the information provided?
Thank you in advance
You might want to create a class to describe the values you are parsing, and define the sorting logic in that class. A simple example,
#interface MyClass : NSObject {
NSNumber *someNum;
NSString *someString;
...
}
#implementation MyClass
- (NSComparisonResult)compareNums:(MyClass *)myClassObject {
return [self.someNum compare:myClassObject.someNum];
}
- (NSComparisonResult)compareStringsDescending:(MyClass *)myClassObject {
return -1 * [self.someString compare:myClassObject.someString];
}
...
Now you can sort many myClass objects by doing this in some viewcontroller:
NSArray *mySortedArray = [self.myOriginalArray sortedArrayUsingSelector:#selector(compareNums:)];
Hope this helps
sortedArray = [array sortedArrayUsingSelector:#selector(compare:)];
Assuming that you have NSNumber's in the array and not something like NSValue or so