In Objective-C, can I declare #property on a c-array of floats? - objective-c

thing.h
#interface Thing : NSObject
{
float stuff[30];
}
#property float stuff;
#end
thing.m
#implementation Thing
#synthesize stuff;
#end
I get error: type of property 'stuff' does not match type of ivar 'stuff'
I don't want to use an NSArray because I'd have to make the floats into NSNumbers (right?) and that's a pain to do math with.
Update: I've noticed similar answers had guesses and trial answers. While I appreciate the attempts by non-Objective-C folks, I'm hoping for a definitive answer whether it's possible or not.

OK, I have compiled up the following code at it works as expected.
FloatHolder.h
#interface FloatHolder : NSObject {
int _count;
float* _values;
}
- (id) initWithCount:(int)count;
// possibly look into this for making access shorter
// http://vgable.com/blog/2009/05/15/concise-nsdictionary-and-nsarray-lookup/
- (float)getValueAtIndex:(int)index;
- (void)setValue:(float)value atIndex:(int)index;
#property(readonly) int count;
#property(readonly) float* values; // allows direct unsafe access to the values
#end
FloatHolder.m
#import "FloatHolder.h"
#implementation FloatHolder
#synthesize count = _count;
#synthesize values = _values;
- (id) initWithCount:(int)count {
self = [super init];
if (self != nil) {
_count = count;
_values = malloc(sizeof(float)*count);
}
return self;
}
- (void) dealloc
{
free(_values);
[super dealloc];
}
- (float)getValueAtIndex:(int)index {
if(index<0 || index>=_count) {
#throw [NSException exceptionWithName: #"Exception" reason: #"Index out of bounds" userInfo: nil];
}
return _values[index];
}
- (void)setValue:(float)value atIndex:(int)index {
if(index<0 || index>=_count) {
#throw [NSException exceptionWithName: #"Exception" reason: #"Index out of bounds" userInfo: nil];
}
_values[index] = value;
}
#end
then in your other application code you can do something like the following:
** FloatTestCode.h **
#import <Cocoa/Cocoa.h>
#import "FloatHolder.h"
#interface FloatTestCode : NSObject {
FloatHolder* holder;
}
- (void) doIt:(id)sender;
#end
** FloatTestCode.m **
#import "FloatTestCode.h"
#implementation FloatTestCode
- (id) init
{
self = [super init];
if (self != nil) {
holder = [[[FloatHolder alloc] initWithCount: 10] retain];
}
return self;
}
- (void) dealloc
{
[holder release];
[super dealloc];
}
- (void) doIt:(id)sender {
holder.values[1] = 10;
}

The type of the property must match the type of the instance variable it will be stored in, so you could do something like
#interface Thing : NSObject
{
float stuff[30];
}
#property float[30] stuff;
#end
and it should work. I wouldn't recommend it though.
I'm guessing you're looking for something like indexed properties from Delphi. The closest you'll get is something like the following.
#interface Thing : NSObject
{
float stuff[30];
}
- (void) setStuff:(float)value atIndex:(int)index;
- (float) getStuffAtIndex:(int)index;
#end

You can't do it the way you want to do it. You can jump through some hoops and get something similar, e.g. using Daniel's solution, but it's not quite the same thing. The reason you can't do it is that arrays are not lvalues in C. An lvalue is something that can appear on the left-hand side of an assignment. The following code is invalid C:
float stuff1[30], stuff2[30];
stuff1 = stuff2; // ERROR: arrays are not lvalues
As a consequence, you can't declare properties whose types are not lvalues.

Daniel's FloatHolder answer has a major bug (edit: he's now fixed it). It only allocates memory for one float and not for the whole array.
The line:
_values = malloc(sizeof(float));
Should be:
_values = malloc(sizeof(float) * count);
Otherwise it seems to be a good answer. Sorry couldn't work out how to reply directly. (edit: I didn't have the necessary privilege on stackoverflow then.)

Even if you could get that to compile, it wouldn't behave well. 'stuff' would return a float*, and the client would have no idea how long the array way; 'setStuff:' would just change the pointer, and you'd either be pointing to stack-allocated data that would vanish out from under you or heap-allocated data that would leak because it wouldn't know to free it.

I'm not well-versed in Objective-C 2.0, but I'm guessing that the issue might be caused by the fact that a C array is essentially just a pointer to the first element of the array, meaning that the type of float stuff[30] is actually float *, not merely a float.

Related

Working with Class, properties and initialization

I'm working on this assignment I found online (Intermediate App Development Using iOS). I'm stuck on part c and d, don't know exactly what its asking me to do.
I know how to print int (%i) and object (%#), but %# print all data? Any help or suggestion will be appreciated.
Part 6
a) Implement class A with properties a1, a2, and a3 (int, string, int).
b) New objects are automatically initialized to 1, "hello", 1
c) Also provide initializer to any data and constructor (called without alloc) to do the same.
d) Make sure %# object of A will print all data.
Here is what I have done so far:
// classA.h
#import <Foundation/Foundation.h>
#interface ClassA : NSObject
// Part 6a
#property int a1;
#property NSString *a2;
#property int a3;
-(ClassA *) initWithA1: (int) x andA2: (NSString *) s andA3: (int) y;
#end
//classA.m
#import "ClassA.h"
#implementation ClassA
-(ClassA *) initWithA1:(int)x andA2:(NSString *)s andA3:(int)y {
self = [super init];
if (self) {
self.a1 = x;
self.a2 = s;
self.a3 = y;
}
return self;
}
// part 6b
-(ClassA *) init {
if (self = [super init]) {
self.a1 = 0;
self.a2 =#"hello";
self.a3 = 0;
}
return self;
}
#end
In reference to part "b" of your question:
As a general rule, only 1 initializer should be doing the "real" work. This is often referred to as the designated initializer. So, your init method should probably read something like:
- (id) init
{
return [self initWithA1:1 andA2:#"hello" andA3:1];
}
As #orbitor wrote, your class should have one designated initialiser.
So, your init method should probably read something like:
- (id) init
{
return [self initWithA1:1 andA2:#"hello" andA3:1];
}
In order to print all object you should implement custom description method:
- (NSString *) description
{
return [NSString stringWithFormat:#"a1 = %d, a2 = %#, a3 = %d", self.a1, self.a2, self.a3];;
}
According to c:
Class method new just calls alloc and init methods so you should only make sure that you wrote properly all initialisers.

iOS Objective-C: NSMutable Array returns garbage

I'm trying to take a C-style vector and convert it into an NSMutable array object.
Here's the function:
+(NSMutableArray*)arrayFromPoints:(vector<Point2f>&)points
{
NSMutableArray* pointArray = [[NSMutableArray alloc] init];
for (int i=0;i<points.size();i++)
{
Point2f point = points[i];
JBPoint* point2 = [[JBPoint alloc]initWithX:point.x andY:point.y];
[pointArray addObject:point2];
}
return pointArray;
}
Custom point class:
#implementation JBPoint
float _x;
float _y;
-(id) initWithX:(float)x andY:(float)y
{
if (self=[super init])
{
_x = x;
_y=y;
}
return self;
}
-(float)x{ return _x;}
-(float)y {return _y;}
#end
Test output:
for (JBPoint* pnt in array)
{
NSLog(#"%f, %f", pnt.x, pnt.y);
}
I except it to output the array, but every time it just gives me the last value! does anyone know why?
I thought that they were maybe pointing to the same object, but they have different memory addresses.
So I figured out the problem. float _x;
float _y; where being treated like class variables instead of instance variables. Changed the class to:
#interface JBPoint()
{
float _x;
float _y;
}
#end
#implementation JBPoint
-(id) initWithX:(float)x andY:(float)y
{
if (self=[super init])
{
_x = x;
_y=y;
}
return self;
}
-(float)x{ return _x;}
-(float)y {return _y;}
#end
if you wrote
#property (nonatomic, readonly) float x;
#property (nonatomic, readonly) float y;
in your header file you wouldn't need to declare the instance variables (and would have avoided the issue here) and you could delete the getter methods your wrote as that would all be generated by the compiler for you and your custom init method would continue to work (with the most recent compiler).
Its a good idea to do this because:
less code
your intent is clear - 2 variables that are readonly for clients
follows language conventions
If you are using an older compiler (an older version of Xcode) then you would also have to #synthesize the accessors like this:
#synthesize x = _x;
Some interesting asides:
With the most recent complier you didn't need the class extension.
#implementation{
float _x;
float _y;
}
would also have worked.
As referenced in WWDC 2012 session video 413, the current recommended pattern to write an init method is:
...
self = [super init];
if (self) {
...
}
return self;

Compiler error "setter method needed" to use dot syntax -- setter is defined

I can't figure out why my getter and setter code is not working. In some example code I was going over:
- (NSArray *)sushiTypes {
return _sushiRolls;
}
- (void)setSushiTypes:(NSArray *)sushiRolls {
[sushiRolls retain];
[_sushiRolls release];
_sushiRolls = sushiRolls;
}
Then in:
- (void)viewDidLoad {
[super viewDidLoad];
self.sushiTypes = [[NSArray alloc]initWithObjects:#"...]autorelease];
}
The whole time, this worked, but a property for sushiTypes was never declared. I (sort of) get how this works, since it works the same as a setter/getter regardless of whether it was synthesized or not.
But here's my code, and I get a compiler error asking for a property. Did I miss something?
#import <Foundation/Foundation.h>
#interface Temp0 : NSObject {
NSNumber *x1;
}
-(NSNumber *)x1;
-(void)setx1:(NSNumber *)x;
#end
//
#import "Temp0.h"
#implementation Temp0
-(NSNumber *)x1 {
return x1;
}
-(void)setx1:(NSNumber *)x {
[x retain];
[x1 release];
x1 = x;
}
-(id)init
{
self.x1 = [[NSNumber alloc]initWithInt:1]; // Error on this line:
// Setter method is needed to assign to object using property assignment syntax
[super init];
}
#end
Screenshot of this code and the error in Xcode
It's standard to capitalize the first letter of the property in the setter method name. As you correctly have in:
-(void)setSushiTypes:(NSArray *)sushiRolls
So setX1: is the expected method signature.
-(void)setX1:(NSNumber *)x1;

NSMutableArray - force the array to hold specific object type only

Is there a way to force NSMutableArray to hold one specific object type only?
I have classes definitions as follow:
#interface Wheel:NSObject
{
int size;
float diameter;
}
#end
#interface Car:NSObject
{
NSString *model;
NSString *make;
NSMutableArray *wheels;
}
#end
How can I force wheels array to hold Wheel objects only with code? (and absolutely not other objects)
Update in 2015
This answer was first written in early 2011 and began:
What we really want is parametric polymorphism so you could declare, say, NSMutableArray<NSString>; but alas such is not available.
In 2015 Apple apparently changed this with the introduction of "lightweight generics" into Objective-C and now you can declare:
NSMutableArray<NSString *> *onlyStrings = [NSMutableArray new];
But all is not quite what it seems, notice the "lightweight"... Then notice that the initialisation part of the above declaration does not contain any generic notation. While Apple have introduced parametric collections, and adding a non-string directly to the above array, onlyStrings, as in say:
[onlyStrings addObject:#666]; // <- Warning: Incompatible pointer types...
will illicit the warning as indicated, the type security is barely skin deep. Consider the method:
- (void) push:(id)obj onto:(NSMutableArray *)array
{
[array addObject:obj];
}
and the code fragment in another method of the same class:
NSMutableArray<NSString *> *oops = [NSMutableArray new];
[self push:#"asda" onto:oops]; // add a string, fine
[self push:#42 onto:oops]; // add a number, no warnings...
What Apple have implemented is essentially a hinting system to assist with automatic inter-operation with Swift, which does have a flavour of type-safe generics. However on the Objective-C side, while the compiler provides some extra hints the system is "lightweight" and type-integrity is still ultimately down to the programmer - as is the Objective-C way.
So which should you use? The new lightweight/pseudo generics, or devise your own patterns for your code? There really is no right answer, figure out what makes sense in your scenario and use it.
For example: If you are targeting interoperation with Swift you should use the lightweight generics! However if the type integrity of a collection is important in your scenario then you could combine the lightweight generics with your own code on the Objective-C side which enforces the type integrity that Swift will on its side.
The Remainder of the 2011 Answer
As another option here is a quick general subclass of NSMutableArray which you init with the kind of object you want in your monomorphic array. This option does not give you static type-checking (in as much as you ever get it in Obj-C), you get runtime exceptions on inserting the wrong type, just as you get runtime exceptions for index out of bounds etc.
This is not thoroughly tested and assumes the documentation on overriding NSMutableArray is correct...
#interface MonomorphicArray : NSMutableArray
{
Class elementClass;
NSMutableArray *realArray;
}
- (id) initWithClass:(Class)element andCapacity:(NSUInteger)numItems;
- (id) initWithClass:(Class)element;
#end
And the implementation:
#implementation MonomorphicArray
- (id) initWithClass:(Class)element andCapacity:(NSUInteger)numItems
{
elementClass = element;
realArray = [NSMutableArray arrayWithCapacity:numItems];
return self;
}
- (id) initWithClass:(Class)element
{
elementClass = element;
realArray = [NSMutableArray new];
return self;
}
// override primitive NSMutableArray methods and enforce monomorphism
- (void) insertObject:(id)anObject atIndex:(NSUInteger)index
{
if ([anObject isKindOfClass:elementClass]) // allows subclasses, use isMemeberOfClass for exact match
{
[realArray insertObject:anObject atIndex:index];
}
else
{
NSException* myException = [NSException
exceptionWithName:#"InvalidAddObject"
reason:#"Added object has wrong type"
userInfo:nil];
#throw myException;
}
}
- (void) removeObjectAtIndex:(NSUInteger)index
{
[realArray removeObjectAtIndex:index];
}
// override primitive NSArray methods
- (NSUInteger) count
{
return [realArray count];
}
- (id) objectAtIndex:(NSUInteger)index
{
return [realArray objectAtIndex:index];
}
// block all the other init's (some could be supported)
static id NotSupported()
{
NSException* myException = [NSException
exceptionWithName:#"InvalidInitializer"
reason:#"Only initWithClass: and initWithClass:andCapacity: supported"
userInfo:nil];
#throw myException;
}
- (id)initWithArray:(NSArray *)anArray { return NotSupported(); }
- (id)initWithArray:(NSArray *)array copyItems:(BOOL)flag { return NotSupported(); }
- (id)initWithContentsOfFile:(NSString *)aPath { return NotSupported(); }
- (id)initWithContentsOfURL:(NSURL *)aURL { return NotSupported(); }
- (id)initWithObjects:(id)firstObj, ... { return NotSupported(); }
- (id)initWithObjects:(const id *)objects count:(NSUInteger)count { return NotSupported(); }
#end
Use as:
MonomorphicArray *monoString = [[MonomorphicArray alloc] initWithClass:[NSString class] andCapacity:3];
[monoString addObject:#"A string"];
[monoString addObject:[NSNumber numberWithInt:42]]; // will throw
[monoString addObject:#"Another string"];
Since Xcode 7, generics are available in Objective-C.
You can declare a NSMutableArray as:
NSMutableArray <Wheel*> *wheels = [[NSMutableArray alloc] initWithArray:#[[Wheel new],[Wheel new]];
The compiler will give you a warning if you try to put non-Wheel objects in the array.
I could be wrong (I'm a noob), but I think, if you create a custom protocol and make sure the objects you are adding to the array follow the same protocol, then when you declare the array you use
NSArray<Protocol Name>
That should prevent objects being added that do not follow the said protocol.
as per i know.. before you added any object in wheels mutableArray, u have to add some check mark. Is the object which i am adding is class "wheel". if it is then add, other wise not.
Example:
if([id isClassOf:"Wheel"] == YES)
{
[array addObject:id)
}
Something like this. i dont remember the exact syntax.
I hope this will help (and work... :P )
Wheel.h file:
#protocol Wheel
#end
#interface Wheel : NSObject
#property ...
#end
Car.h file:
#import "Wheel.h"
#interface Car:NSObject
{
NSString *model;
NSString *make;
NSMutableArray<Wheel, Optional> *wheels;
}
#end
Car.m file:
#import "Car.h"
#implementation Car
-(id)init{
if (self=[super init]){
self.wheels = (NSMutableArray<Wheel,Optional>*)[NSMutableArray alloc]init];
}
return self;
}
#end
Xcode 7 allows you to define Arrays, Dictionaries, and even your own Classes as having generics. The array syntax is as follows:
NSArray<NSString*>* array = #[#"hello world"];
I don't believe there's any way to do it with NSMutableArray out of the box. You could probably enforce this by subclassing and overriding all the constructors and insertion methods, but it's probably not worth it. What are you hoping to achieve with this?
That's not possible; an NSArray (whether mutable or not) will hold any object type. What you can do is to create your own custom subclasses as already suggested by Jim. Alternatively, if you wanted to filter an array to remove objects that weren't of the type you want, then you could do:
- (void)removeObjectsFromArray:(NSMutableArray *)array otherThanOfType:(Class)type
{
int c = 0;
while(c < [array length])
{
NSObject *object = [array objectAtIndex:c];
if([object isKindOfClass:type])
c++;
else
[array removeObjectAtIndex:c];
}
}
...
[self removeObjectsFromArray:array otherThanOfType:[Car class]];
Or make other judgments based on the result of isKindOfClass:, e.g. to divide an array containing a mixture of Cars and Wheels into two arrays, each containing only one kind of object.
You can use the nsexception if you dont have the specific object.
for (int i = 0; i<items.count;i++) {
if([[items objectAtIndex:i] isKindOfClass:[Wheel class]])
{
// do something..!
}else{
[NSException raise:#"Invalid value" format:#"Format of %# is invalid", items];
// do whatever to handle or raise your exception.
}
}
Here's something I've done to avoid subclassing NSMutableArray: use a category. This way you can have the argument and return types you want. Note the naming convention: replace the word "object" in each of the methods you will use with the name of the element class. "objectAtIndex" becomes "wheelAtIndex" and so on. This way there's no name conflict. Very tidy.
typedef NSMutableArray WheelList;
#interface NSMutableArray (WheelList)
- (wheel *) wheelAtIndex: (NSUInteger) index;
- (void) addWheel: (wheel *) w;
#end
#implementation NSMutableArray (WheelList)
- (wheel *) wheelAtIndex: (NSUInteger) index
{
return (wheel *) [self objectAtIndex: index];
}
- (void) addWheel: (wheel *) w
{
[self addObject: w];
}
#end
#interface Car : NSObject
#property WheelList *wheels;
#end;
#implementation Car
#synthesize wheels;
- (id) init
{
if (self = [super init]) {
wheels = [[WheelList alloc] initWithCapacity: 4];
}
return self;
}
#end
protocol maybe a good idea:
#protocol Person <NSObject>
#end
#interface Person : NSObject <Person>
#end
to use:
NSArray<Person>* personArray;
There is one-header file project which allows this:
Objective-C-Generics
Usage:
Copy ObjectiveCGenerics.h to your project.
When defining a new class use the GENERICSABLE macro.
#import "ObjectiveCGenerics.h"
GENERICSABLE(MyClass)
#interface MyClass : NSObject<MyClass>
#property (nonatomic, strong) NSString* name;
#end
Now you can use generics with arrays and sets just as you normally do in Java, C#, etc.
Code:

Help with a method that returns a value by running another object's method

I have a Class that runs the following method (a getter):
// the interface
#interface MyClass : NSObject{
NSNumber *myFloatValue;
}
- (double)myFloatValue;
- (void)setMyFloatValue:(float)floatInput;
#end
// the implementation
#implementation
- (MyClass *)init{
if (self = [super init]){
myFloatValue = [[NSNumber alloc] initWithFloat:3.14];
}
return self;
}
// I understand that NSNumbers are non-mutable objects and can't be
// used like variables.
// Hence I decided to make make the getter's implementation like this
- (double)myFloatValue{
return [myFloatValue floatValue];
}
- (void)setMyFloatValue:(float)floatInput{
if ([self myFloatValue] != floatInput){
[myFloatValue release];
myFloatValue = [[NSNumber alloc] initWithFloat:floatInput;
}
#end
When I mouse over the myFloatValue object during debugging, it does not contain a value. Instead it says: "out of scope".
I would like to be able to make this work without using #property, using something other than NSNumbers, or other major changes since I just want to understand the concepts first. Most importantly, I would like to know what mistake I've apparently made.
I can see a couple of mistakes:
The line #implementation should read #implementation MyClass
The function setMyFloatValue is missing a closing ] and } —it should read:
- (void)setMyFloatValue:(float)floatInput{
if ([self myFloatValue] != floatInput){
[myFloatValue release];
myFloatValue = [[NSNumber alloc] initWithFloat:floatInput];
}
}
I've just tested it in Xcode and it works for me with these changes.
Why not just set property in interface and synthesize accessors in implementation?
#interface MyClass : NSObject {
float *myFloat
}
#property (assign) float myFloat;
#end
#implementation MyClass
#synthesize myFloat;
#end