Shared instance of c file in objective c? - ios

I am working on a chess engine in C/Objective-C and I rewrote a large part of my engine in straight-c to improve the speed. My question is, I have about 3KB of tables I initialize in my C file that I don't want to reinitialize every time a function from this file is called. If this were a regular objective-c class I would create a shared instance. However, the core of my engine is in two .h and a .c files. Should I make all of the tables used by my engine static? Will they persist between multiple other files calling functions in my engine? Should I make a static struct to hold my tables? I'm not sure what the best approach is here. Thanks!
Example:
Test.h:
int getInt(int index);
Test.c:
static int integers[4] = {1,2,3,4};
int getInt(int index) { return integers[index]; }
Every time I call getInt from another file, will it reallocate 'integers'? Or will it reuse the same array? I want to prevent it from unnecessarily reallocating a bunch of static arrays.

Ok, what you did was accessor on a static variable...
A static is only initialized once, so it does get initialized only once per launch.
You can keep it this way, or change it to a global to access it without calling function.
This code could typically get inlined, so changing it to a global is more a matter of taste than performances.
Edit: short summary on allocations
static int array[] = {1, 2}; // Allocated and initialized once
int array2[] = {1, 2, 3}; // Allocated and initialized once
int function() {
int array3[] = {1, 2, 3}; // Allocated and initialized at every call of function();
static int *array4 = malloc(42); // Allocated and initialized once
int *toto = malloc(42); // Allocated at every call of function();
}

Related

Override a static constant int in .h file in Objective-C?

I'm trying to build an app in OC and have a constant in .h file like this that defines how many columns should be on a menu:
// cellManager.h
static int const cellNumberPerRow = 4;
Now in my view manager file(.m), I need to change the number of columns to 3 when the font size changes. So far I have tried:
// menuManagerView.m
if ([self isBigFontSize]) {
// ....
cellNumberPerRow = 3;
// ...
But this gives me an error Cannot assign to variable 'cellNumberPerRow' with const-qualified type 'const int'; And when I tried to add identifier before like this:
static int const cellNumberPerRow = 3;
There is a warning Unused variable 'cellNumberPerRow' and the column number remains 4;
I feel like there should be an elegant way to do this but couldn't find it anywhere. I'm really new to iOS dev so would appreciate anyone's input, Thanks!
UPDATE
I defined a new integer variable, assigned the value of const variable to it, and replaced all old cellNumberPerRoe with the new variable in the .m file. Now it worked. But I wonder if there's any better way to do this?
static int newCellNumberPerRow = cellNumberPerRow;
If you want to change the value of a constant under some circumstances it implies it's no longer a constant. You could circumvent the const compiler check by using a pointer, but that's counterproductive. It'd be much easier to just drop const from definition altogether.
What I would suggest as an alternative is a computed property in your file manager class defined like this:
typedef NS_ENUM(int, CellNumberPerRow) {
defaultCellNumberPerRow = 4,
smallerCellNumberPerRow = 3,
};
#interface YourManager: NSObject
#property(readonly,nonatomic) int currentCellNumberPerRow;
#end
#implementation DocumentItem
-(int)currentCellNumberPerRow {
if ([self isBigFontSize]) {
return smallerCellNumberPerRow;
}
return defaultCellNumberPerRow;
}
#end
Now to get the appropriate cell number per row you would use currentCellNumberPerRow property instead.
Perhaps making the currentCellNumberPerRow a class property #property(class,...) instead of instance property could also turn out convenient.

Vala code with static struct dont works after update to 0.44

Just did a standard job interview is to calculate the volume of water in the histogram. On Monday this code worked, and still works on this site. After updating vala, an error is now displayed.
UPD: more easy example
> Algoritm.vala:2.5-2.16: error: struct `Algotitm.first' cannot be empty
> struct first {
> ^^^^^^^^^^^^ Algoritm.vala:6.5-6.17: error: struct `Algotitm.second' cannot be empty
> struct second {
When posting a question on Stack Overflow it is always good to post an example of the code that is a minimum, complete and verifiable example.
From the link you've provided it appears you have a struct with only members marked as static:
struct First {
static int data;
static int pos;
}
void main () {
}
Marking the fields as static means they aren't instance fields and so the struct is empty of fields. That's why you are getting the error message about the struct being empty. I'm not sure Vala should even allow marking struct fields as static, but it does make sense to allow methods in structs to be static.
You need to remove the static modifiers. This will work:
struct First {
int data;
int pos;
}
void main () {
}
Update
I'm guessing you are trying to write performance optimized code and you think static helps with that. static in Vala means there is no instance data to use. If you are using a data structure like a class or struct then it only makes sense to have instances of those. If you want something to remain unchanged during the running of your program use const in a namespace.
Using a struct may give you a slight performance boost if your are using a very large number in your program. structs created in Vala are allocated on the stack instead of the heap so may be slightly faster. If you are passing structs around you may want to consider [SimpleType] attribute. That means structs will be passed by value in C as well as Vala. Without the [SimpleType] they are copied and passed by reference at the C level, which appears as copy by value in Vala.
Structs in Vala can have initializers (similar to a constructor for a class) and methods. So what I can extract from your second pastebin you could write that as:
struct First {
int data;
int pos;
public First (int[] mass) {
data= 5;
pos = mass.length;
}
public int sas () {
return data + pos;
}
}
void main () {
int[] a = {1,3,0,1,2,3,2,1};
var b = First (a);
print (#"$(b.sas ())\n");
}
That is a follow on question though and should be asked as a second question on Stack Overflow. This is a public forum that follows a format that allows other people to learn from the question and answers.

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.

returning multiple Mat from an OpenCV method

In openCV code sapmles in it's document, I saw they simply pass the Mat as a refrence and fill it.But I have a problem in my code. when i call TestMethod, it doese not fill them.
void TestMethod(Mat a, Mat b)
{
a = imread("img1.jpg");
b = imread("img2.jpg");
return;
}
You might be confused by how OpenCV uses typedefs to hide reference types. I would lookup how typedefs like InputArray are defined, you'll see they have an & in them to make them reference types. cv::Mat is not a typedef so you need to declare it as a reference in the function's argument list.
void TestMethod(Mat& a, Mat& b)
{
a = imread("img1.jpg");
b = imread("img2.jpg");
return;
}
The way you have it written now, a and b are copies of the Mat variables you passed when you called the function. You are just overwriting copies that are deallocating when the function returns.

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