I'm to port some JS to native ObjC code. Since a struct won't fit inside arrays, it needs to be wrapped.
The JS code goes as follows:
var bezierVertices = [{0: 14},{10: 32},{24: 16}];
Plain and easy JS: Array of anonymous objects.
I'm bound to the following requirement: Have the code as compact as possible, meaning I've been refused when proposing an NSArray of NSValue using [NSValue valueWithCGPoint:ccp(x,y)]
Going down the malloc way doesn't fit this criterion either. They want something as compact as the JS stated above.
Before writing something as ugly as an NSString like #"0:14;10:32;24:16"; that's split and parsed in a loop, I thought SO could help bring something clean :)
I'm allowed to use .mm so ObjC++ solutions could fit as well, but I'm not knowledgeable about C++ at all...
Thanks!
J.
They want something as compact as the JS stated above
Who's "they"? Do "they" have any understanding that Objective-C is a compiled language and the "compactness" of the source code is largely irrelevant?
Anyway, rant over. You can make a C array of CGPoints like this:
CGPoint myArray[] = {{0.0, 14.0}, {10.0, 32.0}, {24.0, 16.0}};
This is a standard C array initialiser. You get the number of elements like this:
int nElements = sizeof myArray / sizeof(CGPoint);
If you need to manage variable-length arrays of vertices, C++ provides std::vector<CGPoint>.
Related
I'm quite blank when it comes to swift, I've been developing using Obj-c. But a tutorial that I've been following uses Swift. Can anyone help me convert the following line of Swift into Objective-C. It's basically to load a String onto an Array.
self.iDArray.append(objectIDs[i].valueForKey("objectId") as! String)
self.iDArray.append(objectIDs[i].valueForKey("objectId") as! String)
Should be
[self.iDArray append: [objectIDs[1].valueForKey: #"objectID"]]
However, the Swift code is force-casting [objectIDs[1].valueForKey: #"objectID"] to type String (A Swift string).
That suggests to me that self.iDArray may be a Swift array. Swift arrays normally contain only a single type. You create an array of String objects, or an array of Dictionary objects. You can also create an array of AnyObject.
NSArray is an array of id type.
I'm not 100% positive how to force-cast to String type in Objective-C. maybe:
[self.iDArray append: (String) [objectIDs[1] valueForKey: #"objectID"]]
On the surface, objectIDs[x] appears to be a dictionary, and the compiler will give you a break on types if you dereference it that way. So naive to parse, a usable syntax would be:
[self.iDArray append:objectIDs[1][#"objectId"]];
But that's incorrect semantically for parse, since the implication is that the objectIDs array is implied to contain parse objects (named confusingly with the "IDs" suffix). If it's really parse objects, then the collection style reference for objectId won't work, and should be instead
[self.iDArray append:((PFObject *)objectIDs[1]).objectId];
Or more readably:
PFObject *object = objectIDs[1];
NSString *objectId = object.objectId;
[self.iDArray append:objectId];
But, along the same lines semantically, the implication of the code is that it's adding to an NSMutable array, so it probably should be -- for any of the above suggestions:
[self.iDArray addObject: .....
Stop reading here if you care only about compiling and executing without a crash.
But, even if all that's right, which I think can be inferred from the code, it's indicative of bad design in my opinion. Swift developers in particular seem to have a penchant for saving off objectIDs and passing them around as proxies for object, and in so doing, loosing all of the other valuable stuff in the PFObject.
My practice is, wherever possible, just keep and pass the whole PFObject. You can always ask it for its objectId, later. More strongly, my rule of thumb when reading code is: show me parse.com code that refers much to objectIds -- except for things like equality tests -- and I'll show you a design error.
I'm trying to do the following, but NSValue's creation method returns nil.
Are C bitfields in structs not supported?
struct MyThingType {
BOOL isActive:1;
uint count:7;
} myThing = {
.isActive = YES,
.count = 3,
};
NSValue *value = [NSValue valueWithBytes:&myThing objCType:#encode(struct MyThingType)];
// value is nil here
First and foremost, claptrap makes a very good point in his comment: why bother using bitfield specifiers (which are mainly used to either do micro-optimization or manually add padding bits where you need them), to then wrap it all up in an instance of NSValue).
It's like buying a castle, but then living in the kitchen to not ware out the carpets...
I don't think it is, a quick canter through the apple dev-docs came up with this... there are indeed several issues to take into account when it comes to bit fields.
I've also just found this, which explains why bit-fields + NSValue don't really play well together.
Especially in cases where the sizeof a struct can lead to NSValue reading the data in an... shall we say erratic manner:
The struct you've created is padded to 8 bits. Now these bits could be read as 2 int, or 1 long or something... From what I've read on the linked page, it's not unlikely that this is what is happening.
So, basically, NSValue is incapable of determining the actual types, when you're using bit fields. In case of ambiguity, an int (width 4 in most cases) is assumed and under/overflow occurs, and you have a mess on your hands.
Since the compiler still has some liberty as to where what member is actually stored, it doesn't quite suffice to pass the stringified typedef sort of thing (objCType: #encode(struct YourStruct), because there is a good chance that you won't be able to make sense of the actual struct itself, owing to compiler optimizations and such...
I'd suggest you simply drop the bit field specifiers, because structs should be supported... at least, last time I tried, a struct with simple primitive types worked just fine.
You can solve this with a union. Simply put the structure into union that has another member with a type supported by NSValue and has a size larger than your structure. In your case this is obvious for long.
union _bitfield_word_union
{
yourstructuretype bitfield;
long plain;
};
You can make it more robust against resizing the structure by using an array whose size is calculated at compile time. (Please remember that sizeof() is a compile time operator, too.)
char plain[(sizeof(yourstructuretype)/sizeof(char)];
Then you can store the structure with the bitfield into the union and read the plain member out.
union converter = { .bitfield = yourstructuretypevalue };
long plain = converter.plain;
Use this value for NSValue instance creation. Reading out you have to do the inverse way.
I'm pretty sure that through a technical correctum of C99 this became standard conforming (called type punning), because you can expect that reading out a member's value (bitfield) through another members value (plain) and storing it back is defined, if the member being read is at least as big as the member being written. (There might be undefined bits 9-31/63 in plain, but you do not have to care about it.) However it is real-world conforming.
Dirty hack? Maybe. One might call it C99. However using bitfields in combination with NSValue sounds like using dirty hacks.
I've been developing iOs and OsX applications for several months now and it still feels like I'm doing something wrong. I try to stick to the Guidelines and I try to use the objects Apple provides as often as I can. But it seems they are making my code very hard to understand.
Example:
When I want to just "increment" a NSNumber Object (which is not mutable, but you get what I mean), I use awkward lines like this:
int value = [counter intValue];
counter = [NSNumber numberWithInt:value +1];
Is this really necessary? Are there more elegant ways (i++, inc(i), etc) to do simple things like this? Especially when you're working with coordinates it gets really frustrating and hard to work with.
When working with Objective C I feel like I'm allocating, deallocating and converting objects all the time and wasting so much of my own time and the CPU time with all those conversions. Thanks for your time, I really appreciate your answers and I'm looking forward to your tipps!
Using your example, is there any particular reason you are using NSNumber for a counter? It would be much better to use int so that you can use value++.
The key to good Objective-C code is to use objects when they make sense. Don't be afraid to use non-object data types and don't be afraid to drop down (not the best term) to C when required.
As #sosborn wrote: use objects only when it's required. But: when it's required, and you still feel wrong, simply don't. Write a macro for incrementing an NSNumber, use ARC for let the compiler do the memory management for you as efficiently as possible, etc. If you really worried about time, use C or assembly for time-critical tasks, or C++ if you want OO.
P. s.: NSNumber increment macro:
#define NSNUM_INC(n) do { n = [NSNumber numberWithInt:[n intValue] + 1]; } while (0);
You can write your category for NSNumber to implement the methods you need. For your example the file of category contains the following function:
-(NSNumber *)numberByAddingInt:(int)i
{
...
}
Include this file and then you can call it as:
counter = [counter numberByAddingInt:1];
I have a game object which processed in two completely different places. In Contact Listener i check some conditions and if they occur i must save one or more portions of complex data. So i decided to use struct. For example:
struct SomeStruct
{
int value1;
int value2;
CGPoint value3;
b2Vec2 value4;
};
typedef SomeStruct SomeStruct;
In Game Scene i go through all game objects and if its the stack/array not empty, do some stuff and wipe it.
In Contact Listener it repeats from the beginning.
I must use this architecture because of strict order of execution (method must be called after other methods).
I suspect that i need something like vector or NSMutableArray (i think it will not work with struct), so vector may the the only way.
But don't understand how to achieve it. May you help me with some code/pseudocode or link to the book/article where i can found a solution?
Cocoa provides NSValue class for that purpose:
This creates an object that you can add to NSMutableArray:
NSValue *someObj = [NSValue valueWithBytes:&myStruct objCType:#encode(SomeStruct)];
You can use [someObj pointerValue] to access a void* representing the address of the structure that you put in NSValue.
There is a lot of solutions for this problem.
Don't use struct. An obj-c class is practically the same thing as a struct.
Use CFArray (CFArrayCreateMutable) and put it there as a pointer.
Use a C++ class with STL vector.
Use a C array (SomeStruct[]) and increase its length when you need it.
Use a classic implementation of a stack, with a linked list (every struct has a pointer to the next value).
Apologies or asking what is probably a very straightforward question, but I'm new to C-Syntax languages in general and have found something that confused me.
I've see a couple of example bits of code that create a CGFloat object and then seem to treat them as a implicit array of some kind, for example.
CGFloat newFloat[3] = {value1,value2,value};
Is this a generally valid concept in objective C to create arrays, or is it something built into CGFloat to hand 3D points in space?
Many thanks for any help.
This is called array initialisation and is a part of the language.
The {value1,value2,value} part is called an initialiser and can be used on the right side of the assignment whenever defining an array. When the number of elements in the initialiser corresponds to the specified size of the array, you don't actually need to explicitly specify the size:
CGFloat newFloat[] = {value1, value2, value};
This makes the maintenance easier since adding a new element at the end doesn't force you to update the size as well.
Such initialisers are supported for structs as well.
That's not an implicit array, the left hand side explicitly declares a variable that is a CGFloat array of length 3. The syntax is actually part of the C standard.