Best way to pass CGFloat by reference to another class - ios

In ClassA, I have a CGFloat value x that I want to pass by reference to ClassB such that if I make a change to the CGFloat in ClassA, it will be reflected in the reference to x in ClassB. Also, when I pass it to ClassB, I want to store it as a property.
I've thought about using a CGFloat pointer, but I'm struggling to figure out the proper syntax to make it a property:
#property(nonatomic) CGFloat *x;
And then to dereference it:
self->x
I thought about using NSNumber but there is no way to set the value using NSNumber such that it will update in ClassB. I thought about giving up and making a wrapper class to store the CGFloat, but this seems like overkill.
What is the best pattern to go about doing this?

I thought about giving up and making a wrapper class to store the CGFloat, but this seems like overkill.
The advantage of this approach is safety, you create an object, both classes reference it, and ARC takes care of the memory management.
The class is easy to define, for example:
#interface ABShare1 : NSObject
#property CGFloat x;
#end
#implementation ABShare1
#end
(in a .h & .m file – same for other examples)
A class using this would be something like:
#implementation ClassA
{
ABShare1 *one;
}
...
one = ABShare1.new; // somewhere in initialisation
...
... one.x = 42; ... z = one.x * 24; ...
Note: the above stores the ABShare1 reference in a private instance variable, you can store it in a property if you wish but there is no need to.
You can call a method on another class passing the object, e.g.:
ClassB *myB;
...
[myB using:(ABShare1 *)sharedVariable];
and that other class can keep the reference as long as it requires, memory management is automatic.
I've thought about using a CGFloat pointer
This is the standard C (a subset of Objective-C) way of "passing by reference".
You can store a CGFloat * in a property, all "object" valued properties in Objective-C just store pointers (e.g. #property NSString *name; stores a pointer to an NSString object).
You must create the variable that the CGFloat * references, the equivalent of new or alloc/init in Objective-C. You can use the address of a variable, e.g. something like:
CGFloat actualX;
CGFloat *x = &actualX;
but you have to manually ensure that the referenced variable, actualX, lives at least as long as its pointer, stored in x, is in use – failure to do that results in a dangling pointer.
The other option is to dynamically allocate the storage, the direct equivalent of new, e.g. something like:
CGFloat *x = malloc(sizeof(CGFloat));
However you are now responsible for determining when the storage is no longer required and releasing it (using free()).
The first solution to you is "overkill" – maybe because while you are freed from concerns over memory management you don't get a "variable" but two functions/methods to get/set a value.
The second solution is closest to feeling like a "variable", you just use *sharedVariable rather than sharedVariable. However while the manual memory management required is standard for C programmers, it is not for Objective-C programmers.
A third approach mixes the two building on how structures (struct) in C can be used: to share a collection of variables rather than share each one individually by address, instead define a struct with a member for each variable, allocate one and share its address, something like:
typedef struct ABShare
{ CGFloat x;
CGFloat y;
} ABShare;
ABShare *one = malloc(sizeof(ABShare));
one->x = 42;
one->y = 24;
The above has the same memory management issues as the second solution, but we can convert it to a very close Objective-C equivalent:
#interface ABShare : NSObject
{
#public // required
CGFloat x;
CGFloat y;
}
#end
#implementation ABShare
#end
Note: Objective-C classes are effectively implemented using structs, indeed the first Objective-C compilers actually translated them into C struct code.
Using this is very close to the C:
ABShare *one = ABShare.new;
one->x = 42;
one->y = 24;
Same "variable" look as C but with automatic memory management.
This last scheme is essentially how Objective-C manages sharing variables when a block is created – all the local variables accessed by the block are moved into a dynamically allocated object/struct and the variables then accessed using ->.
Which is best in Objective-C? The first and the third are both "Objective-C" style, the second is usually avoided accept when interacting with C APIs. Of the first and third pick whichever feels "right" semantically, rather than concerns over performance, to you. HTH

[NSMutableData dataWithLength:sizeof(CGFloat)] and cast mutableBytes to CGFloat*
You can implement getter and setter of property #property(nonatomic) CGFloat x -without pointer

Related

Why is instancetype used?

Can someone please explain to me (in simple terms) why an instancetype is used in Objective-C?
- (instancetype) init {
self = [super init];
if (self) {
// Custom initialization
}
return self;
}
It's to increase type safety.
Back in the old days, initialisers just returned an object of type id (any object).
With normal initialisers (those that begin with "init", "alloc" or "new"), this wasn't usually a problem. The compiler would automatically infer the type that it returned and therefore restrict any method calls on the object to the instance methods of that class.
However, this was a problem with static convenience initialisers or "factory methods" that didn't necessarily follow the same naming convention - therefore it was unable to apply the same type safety.
This means that with a class like this:
#interface Foo : NSObject
+(id) aConvenienceInit;
#end
The compiler would accept code like this:
NSArray* subviews = [Foo aConvenienceInit].subviews;
Why? Because the returned object could be any object, so if you try and access a UIView property - there's no type safety to stop you.
However, now with instancetype, the result you get back is of type of your given instance. Now with this code:
#interface Foo : NSObject
+(instancetype) aConvenienceInit;
#end
...
NSArray* subviews = [Foo aConvenienceInit].subviews;
You'll get a compiler warning saying that the property subviews is not a member of Foo*:
Although it's worth noting that the compiler will automatically convert the return type from id to instancetype if your method begins with "alloc", "init" or "new" - but nonetheless using instancetype wherever you can is a good habit to get into.
See the Apple docs on instancetype for more info.
Imagine two classes:
#interface A : NSObject
- (instancetype)init;
#end
#interface B : A
#end
The init method from A is inherited to B. However, in both classes the method has a different return type. In A the return type is A and in B the return type is B.
There is no other way to declare the return type for initializers correctly. Note that most programming languages with classes don't even have return types for constructors, therefore they completely avoid the issue.
This is the reason why Obj-C needs instancetype but of course it can be used outside initializers, too.
It is important to use instancetype instead of id in Objective-C if you are also using this code in Swift. Consider the following class declaration:
#interface MyObject : NSObject
+ (id)createMyObject;
- (void)f;
#end
If you want to create a MyObject instance in Swift 5.3 with createMyObject and then call f for this object, you will have to do the following:
let a = MyObject.createMyObject()
(a as? MyObject)?.f()
Now replace id with instancetype in MyObject to have the following Swift code:
let a = MyObject.create()
a?.f()
As you can see now, you can use MyObject.create() instead of MyObject.createMyObject(). And you don't need to use (a as? MyObject) since a is defined as MyObject? and not as Any.

C-Style 2D Array as ivar

In C, we could do the following to create a 2D array:
int intArray[10][10];
In C99, we could create a VLA:
size_t col = 10;
size_t row = 10;
int array[row][col];
Within a method in Objective-C, I can create a 2D array that hold ids as follows:
id genObjectArray[10][10];
Is it possible to create an 2d array ivar in Objective-C?
The following is what I have tried:
#interface myClass ()
{
id objArray[][];
//This doesn't work, unless I specific size.
//I want to do this, so that I could specific the size later during
//runtime
}
In C, I could do the following and allocate space for a 2D array later within a block scope:
int **array;
int *elements;
I can do the same within Objective-C, too, but the problem arises when I use id or other object types; other words, the following is not valid:
id **array;
id *elements;
Thus, my question is, is it possible to declare a C-style 2D array as ivar that holds ids?
I understand that we could achieve that using normal NS(Mutable)Array; but this just serves for educational purposes.
You can't do this. For a C99 VLA, the space required for the array is allocated at the point the array is declared. For an ivar, the analogous time to do that would be when the object was allocated and initialized, but there's no support in Objective C to do that. You'd need to have a stronger definition of what an object constructor can do (more like Java's constructors than Objective C's initializers).
The closest you can get would be something like this:
#interface myClass () {
id * objArray;
}
-(instancetype)initWithRow:(size_t)row col:(size_t)col {
self = [super init];
if (self) {
objArray = calloc(row * col * sizeof(id));
}
return self;
}
-(void)dealloc {
free(objArray);
}
In that case, you're declaring the ivar as a pointer and managing the storage yourself (and the stride, for a multi-dimensional array).
Obviously, NSArray is better in all possible ways.

Non-Object Attribute in Core Data, transient properties

Feel lost after reading this section: A Non-Object Attribute
According to the Basic-Approach also contained in above link, I should have 2 attributes in my custom-code when handling "transient properties":
1st attribute, for the actually-wanted (un-supported) custom type => transient attribute
2nd attribute, for shadow-representation (concrete supported) type => persistent attribute
......
My reading was very enjoyable, until reached "A Non-Object Attribute" section, which puzzle me deeply, as quoted below:
...When you implement the entity’s custom class, you typically add an instance variable for the attribute. ...
《 OK, I can follow this...make an iVar is no big deal》
If you use an instance variable to hold an attribute, you must also implement primitive get and set accessors
《 OK, I know how to do primitive-accessor. why need them? because internal-optimized-storage inside MO can be efficiently used, I guess.》
#interface MyManagedObject : NSManagedObject
{
 NSRect myBounds; // I assume this suppose to be the **transient attribute**
}
#property (nonatomic, assign) NSRect bounds; // I assume this is the **persistent attribute**
#property (nonatomic, assign) NSRect primitiveBounds; // because complier forces me to implement below primitive-accessors ?
#end
- (NSRect)primitiveBounds
{
return myBounds; // accessing iVAR storage for **transient attribute**? I hope so
}
- (void)setPrimitiveBounds:(NSRect)aRect
myBounds = aRect; // accessing iVAR storage for **transient attribute**? I hope so
}
From here down below, I have... too many ???????????? unsolved
- (NSRect)bounds
{
[self willAccessValueForKey:#"bounds"]; //KVO notice of access **persistent attribute**, I guess
NSRect aRect = bounds; //will this invoke primitive-Getter ???
[self didAccessValueForKey:#"bounds"];
if (aRect.size.width == 0) //bounds has not yet been unarchived, Apple explained
 {
NSString *boundsAsString = [self boundsAsString]; // unarchiving pseudo method, I guess
if (boundsAsString != nil) //if that value is not nil, transform it into the appropriate type and cache it...Apple explained.
{
bounds = NSRectFromString(boundsAsString); //will this invoke primitive-Setter???
}
}
return bounds;
}
I put my final question list here:
1, do I STILL need to have 2 attributes to handle NON-Object-Attribute, transient attribute and persistent attribute?
2, how can iVar "myBounds" be represented/connected with "#property bounds"? Is this "#property bounds" the modeled-property in a MOM?
3, what is the purpose of implementation of primitive-accessor here? for enforcing me write KVO (will...did...) methods pair? for transferring values (in and out) between iVar "myBounds"and "#property bounds"?
4, in this line of code
bounds = NSRectFromString(boundsAsString); //will this invoke primitive-Setter???
is primitive-Setter called OR public/standard-Setter gets called? Why?
In iOS, there are the very convenient NSStringFromCGRect and CGRectFromNSString functions. Why not just use those and store a string?
Your questions:
Yes, you need the 2 attributes, as explained in the documentation.
Yes, this is based on the managed object model. The primitiveX name for x is generated / interpreted automatically.
You need the primitive accessor methods here to make it KVC - which is not the case with primitives.

Objective C: Good way to define C array like MyStruct theArray[18][18]?

I need to use something like a C array:
MyStruct theArray[18][18];
but I cannot define it as a property:
#property (nonatomic) MyStruct theArray[18][18];
then I have to:
#implementation MyClass
{
MyStruct theArray[18][18];
}
But is this good in term of modern Objective C guideline?
Thanks
Update:
I know I can define the struct as class and use NSMutableArray to handle it, but it is more convenient to use the C array in my case, the main concern is coding guideline and memory issue, as I do not allocate or release the theArray[18][18], not sure what its life cycle is, and I'm using ARC.
Properties cannot be of array type, while public instance variables do not provide sufficient encapsulation. A more Objective C - like approach would be defining a private 2D array, and a pair of methods or a method returning a pointer to access it - something along these lines:
// For small structs you can use a pair of methods:
-(MyStruct)getElementAtIndexes:(NSUInteger)i and:(NSUInteger)j;
-(void)setElementAtIndexes:(NSUInteger)i and:(NSUInteger)j to:(MyStruct)val;
// For larger structs you should use a single method that returns a pointer
// to avoid copying too much data:
-(MyStruct*)elementAtIndexes:(NSUInteger)i and:(NSUInteger)j;
How about use pointers instead?
#property (nonatomic) MyStruct **theArray;
The answers so far are great. . . here's two more options:
1. A bit hacky
(I'm not sure if this requires Objective-C++)
You can create the array as a public property like so:
#interface MyClass
{
#public:
MyStruct theArray[18][18];
}
#end
And then access it as follows:
myClass->theArray
2. Return a Struct
While you can't return a C-style array, you can return a struct:
typedef struct
{
CGPoint textureCoordinates[kMaxHillVertices];
CGPoint borderVertices[kMaxBorderVertices];
} HillsDrawData;
#interface Hills : NSObject
{
HillsDrawData _drawData;
}
- (HillsDrawData)drawData; //This will get cleaned up when the class that owns it does.
#end

Xcode / iOS: Simple example of a mutable C-Array as a class instance variable?

For some reason I just cant seem to get my head around the process of creating a C-Array instance variable for a class that can have elements added to it dynamically at runtime.
My goal is to create a class called AEMesh. All AEMesh objects will have a c-array storing the vertexdata for that specific AEMesh's 3D model for use with OpenGL ES (more specifically it's functionality for drawing a model by passing it a simple C-Array of vertexdata).
Initially I was using an NSMutableArray, on the assumption that I could simply pass this array to OpenGL ES, however that isnt the case as the framework requires a C-Array. I got around the issue by essentially creating a C-Array of all of the vertexdata for the current AEMesh when it came time to render that specific mesh, and passing that array to OpenGL ES. Obviously the issue here is performance as I am constantly allocating and deallocating enough memory to hold every 3D model's vertexdata in the app about a dozen times a second.
So, Im not one to want the answer spoon fed to me, but if anyone would be willing to explain to me the standard idiom for giving a class a mutable c-array (some articles Ive read mention using malloc?) I would greatly appreciate it. From the information Ive gathered, using malloc might work, but this isn't creating a standard c-array I can pass in to OpenGL ES, instead its more of a pseudo-c-array that works like a c-array?
Anyways, I will continue to experiment and search the internet but again, if anyone can offer a helping hand I would greatly appreciate it.
Thanks,
- Adam Eisfeld
The idea would just be to add a pointer to an array of AEMesh structures to your class, and then maintain the array as necessary. Following is a little (untested) code that uses malloc() to create such an array and realloc() to resize it. I'm growing the array 10 meshes at a time:
#interface MyClass : NSObject
{
int meshCount;
AEMesh *meshes;
}
#end
#implementation MyClass
-(id)init {
if ((self = [super init])) {
meshCount = 0;
meshes = malloc(sizeof(AEMesh)*10);
}
return self;
}
-(void)addMesh:(AEMesh)mesh {
if (meshCount % 10 = 0) {
meshCount = realloc(sizeof(AEMesh) * (meshCount + 10));
}
if (meshCount != nil) {
meshes[meshCount] = mesh;
meshCount++;
}
}
#end
It might be worthwhile to factor the array management into it's own Objective-C class, much as Brian Coleman's answer uses std::vector to manage the meshes. That way, you could use it for C arrays of any type, not just AEMesh.
From the information Ive gathered, using malloc might work, but this
isn't creating a standard c-array I can pass in to OpenGL ES, instead
its more of a pseudo-c-array that works like a c-array?
A C array is nothing more than a series of objects ("objects" used here in the C sense of contiguous memory, not the OO sense) in memory. You can create one by declaring it on the stack:
int foo[10]; // array of 10 ints
or dynamically on the heap:
int foo[] = malloc(sizeof(int)*10); // array of 10 ints, not on the stack
int *bar = malloc(sizeof(int)*10); // another way to write the same thing
Don't forget to use free() to deallocate any blocks of memory you've created with malloc(), realloc(), calloc(), etc. when you're done with them.
I know it doesn't directly answer your question, but an even easier approach would be to work with an NSMutableArray instance variable until the point where you need to pass it to the API, where you would use getObjects:range: in order to convert it to a C-Array. That way you won't have to deal with "mutable" C-Arrays and save yourself the trouble.
If you're willing to use ObjectiveC++ and stray outside the bounds of C and ObjectiveC, then you can use a std::vector to amortise the cost of resizing the array of vertex data. Here's what things would look like:
include <vector>
include <gl.h>
#interface MyClass {
std::vector<GLfloat> vertexData;
}
-(void) createMyVertexData;
-(void) useMyVertexData;
#end
#implementation
-(void) createMyVertexData {
// Erase all current data from vertexData
vertexData.erase(vertexData.begin(),
std::remove(vertexData.begin(),
vertexData.end());
// The number of vertices in a triangle
std::size_t nVertices = 3;
// The number of coordinates required to specify a vertex (x, y, z)
std::size_t nDimensions = 3;
// Reserve sufficient capacity to store the vertex data
vertexData.reserve(nVertices * nDimensions);
// Add the vertex data to the vector
// First vertex
vertexData.push_back(0);
vertexData.push_back(0);
vertexData.push_back(0);
// And so on
}
-(void) useMyVertexData {
// Get a pointer to the first element in the vertex data array
GLfloat* rawVertexData = &vertexData[0];
// Get the size of the vertex data
std::size_t sizeVertexData = vertexData.size();
// Use the vertex data
}
#end
The neat bit is that vertexData is automatically destroyed along with the instance of MyClass. You don't have to add anything to the dealloc method in MyClass. Remember to define MyClass in a .mm file

Resources