What is the swift equivalent of this cast? - objective-c

I want to convert this into swift, or at least find something that does the same thing.
size_t width = CGImageGetWidth(spriteImage);
size_t height = CGImageGetHeight(spriteImage);
GLubyte * spriteData = (GLubyte *) calloc(width*height*4, sizeof(GLubyte));
I need to initialize the spriteData pointer in swift of the right size.

The first two of those are of type size_t, which maps to Uint in Swift, and the last is GLubyte, which maps to UInt8. This code will initialize spriteData as an array of GLubyte, which you could pass to any C function that needs an UnsafeMutablePointer<GLubyte> or UnsafePointer<GLubyte>:
let width = CGImageGetWidth(spriteImage)
let height = CGImageGetHeight(spriteImage)
var spriteData: [GLubyte] = Array(count: Int(width * height * 4), repeatedValue: 0)
What do you need to do with spriteData?

The straightforward way is:
var spriteData = UnsafeMutablePointer<GLubyte>.alloc(Int(width * height * 4))
Note that, if you did this, you have to dealloc it manually.
spriteData.dealloc(Int(width * height * 4))
/// Deallocate `num` objects.
///
/// :param: num number of objects to deallocate. Should match exactly
/// the value that was passed to `alloc()` (partial deallocations are not
/// possible).

Related

calloc in Swift

How do I transform the following ObjectiveC statements into SWIFT:
UInt32 *pixels;
pixels = (UInt32 *) calloc(height * width, sizeof(UInt32));
I tried to do the following:
var pixels: UInt32
pixels = (UInt32)calloc(height * width, sizeof(UInt32))
and I receive the error message:
Int is not convertible to UInt
and the (UInt32) Casting didn't work as well.
Can someone give me some advice please? I am struggling a little bit with SWIFT still. Thank you.
Here's an easier way of allocating that array in swift:
var pixels = [UInt32](count: height * width, repeatedValue: 0)
If that's what you actually want to do.
But, if you need a pointer from calloc for some reason, go with:
let pixels = calloc(UInt(height * width), UInt(sizeof(UInt32)))
The type of pixels though must be a type of UnsafeMutablePointer<T>, and you would handle it like a swift pointer in the rest of your code.
For Swift-3 :
UnsafeMutablePointer is replace by UnsafeMutableRawPointer
var pixels = UnsafeMutableRawPointer( calloc(height * width, MemoryLayout<UInt32>.size) )
Reference
If you really know what you are doing and insist in allocating memory unsafely using calloc:
var pixels: UnsafeMutablePointer<UInt32>
pixels = calloc(height * width, sizeof(UInt32))
or just
var pixels = calloc(height * width, sizeof(UInt32))

How can I deal with operation between Int and CGFloat?

In Objective-C I can do the following operation:
Objective-C code:
CGFloat width = CGRectGetWidth(mView.bounds);
CGFloat total = width*[myArray count];
but in Swift, it will raise an error:
Could not find an overload for '*' that accepts the supplied arguments
How can I avoid this situation elegantly?
First, let's create some demo data
let array: NSArray = ["a", "b", "c"] //you could use a Swift array, too
let view = UIView() //just some view
Now, everything else works almost the same way as in Obj-C
let width: CGFloat = CGRectGetWidth(view.bounds)
or simply
let width = CGRectGetWidth(rect) //type of the variable is inferred
and total:
let total = width * CGFloat(array.count)
Note that we have to add a CGFloat cast for array.count. Obj-C would implicitly cast NSUInteger to CGFloat but Swift has no implicit casts, so we have to add an explicit one.
In Swift you cannot multiply two numbers of different types (NSNumber, Int, Double, etc.) directly. The width of a CGRect is of floating point type and the array count is of integer type. Here's a working example:
let myArray: Int[] = [1,2,3]
let rect: CGRect = CGRect(x:0,y:0,width:100,height:100)
let total: Double = rect.size.width * Double(myArray.count)
Swift does not allow operations between two numbers of different types. Therefore, before to multiply your array.count (Int) by your width (CGFloat), you'll have to cast it to CGFloat.
Fortunately, Swift provides a simple CGFloat initializer init(_:) that creates a new CGFloat from an Int. This initializer has the following declaration:
init<Source>(_ value: Source) where Source : BinaryInteger
Creates a new value, rounded to the closest possible representation.
The Swift 5 Playground sample code below shows how to perform your calculation by using CGFloat's initializer:
import UIKit
import CoreGraphics
// Set array and view
let array = Array(1...3)
let rect = CGRect(x: 0, y: 0, width: 100, height: 100)
let view = UIView(frame: rect)
// Perform operation
let width = view.bounds.width
let total = width * CGFloat(array.count)
print(total) // prints: 300.0
need to change All Int to CGFloat Type, or change All CGFloat to Int
let a: CGFloat = 0.25
let b: Int = 1
// wrong: Binary operator '*' cannot be applied to operands of type 'CGFloat' and 'Int'
// let c = a * b
// right: change All Int to CGFloat Type
let r = a * CGFloat(b)
// right: change All CGFloat to Int
let r = Int(a) * b

Empty float ** for sound samples

I have been attempting to pass and array to a method within DiracLE audio library.
The array looks like this in the debugger
- (OSStatus) readFloatsConsecutive:(SInt64)numFrames intoArray:(float**)audio withOffset:(long)offset
That fills the array up like so
if (audio) {
for (long c = 0; c < mExtAFNumChannels; c++) {
if (!audio[c]) continue; // this executes for both channels
// but doesnt proceed into next for loop
for (long v = 0; v < numFrames; v++) {
if (v < loadedPackets) audio[c][v+offset] = (float)data[v*mExtAFNumChannels+c] / 32768.f;
else audio[c][v+offset] = 0.f;
}
}
}
I call it like this
[reader readFloatsConsecutive:frameCount intoArray:arrayToFill];
arrayToFill being an argument to the current function scope
[self readAudioDataForFile:temp withArray:tempArray];
The array was initially passed into the function like this
// this array was passed into the function as tempArray which is float **tempArray = NULL;
arrayToFill = (float **) malloc ( (frameCount * channelCount) * sizeof( float ));
As I needed to extract audio data from the file in my method I have to malloc the array there and pass it into the dirac function for filling. I malloc like so arrayToFill = (float **) malloc ( (frameCount * channelCount) * sizeof( float )); and then pass it to the dirac function as mentioned before.
This array could be a 2 dimensional or 1 dimensional array depending on channel count
The problem relies on allocation in my opinion.
Allocating a 1 dimensional array would look like:
arrayToFill = (float *) malloc ( (frameCount * channelCount) * sizeof( float ));
and it would be enought.
Allocating a 2 dimensional array would be different though, because you have to allocate even inner arrays. If I understood correctly if you have two channels then the array is bidimensional, you should do something like:
arrayToFill = (float **)calloc(channelCount, sizeof(float*));
for (int i = 0; i < channelCount; ++i)
arrayToFill[i] = (float*)calloc(frameCount, sizeof(float));
This because you need to allocate a pointer to pointer to float. So in the first step you allocate a 2 dimensional array of pointers to float, these pointers are initialized to NULL so you have to loop through it and allocate them separately.
If the channel is inner inside the array (eg. the first index chooses the frame and not the channel) then you should swap dimensions.

Objective-c: Adding a custom object to a NSMutableArray

I usually program in java or c++ and I recently started with objective-c. Looking for vectors in objective-c, I found NSMutableArray which seems to be the best option. I'm working on an opengl game and I'm trying to create an NSMutableArray of textured quads for my sprites. Here is the relevant code:
I define textured quads:
typedef struct {
CGPoint geometryVertex;
CGPoint textureVertex;
} TexturedVertex;
typedef struct {
TexturedVertex bl;
TexturedVertex br;
TexturedVertex tl;
TexturedVertex tr;
} TexturedQuad;
I create an array in the interface:
#interface Sprite() {
NSMutableArray *quads;
}
I initiate the array and I create the texturedQuads based on "width" and "height", which are the dimensions of a single sprite, and "self.textureInfo.width" and "self.textureInfo.height", which are the dimensions of the entire sprite sheet:
quads = [NSMutableArray arrayWithCapacity:1];
for(int x = 0; x < self.textureInfo.width/width; x++) {
for(int y = 0; y < self.textureInfo.height/height; y++) {
TexturedQuad q;
q.bl.geometryVertex = CGPointMake(0, 0);
q.br.geometryVertex = CGPointMake(width, 0);
q.tl.geometryVertex = CGPointMake(0, height);
q.tr.geometryVertex = CGPointMake(width, height);
int x0 = (x*width)/self.textureInfo.width;
int x1 = (x*width + width)/self.textureInfo.width;
int y0 = (y*height)/self.textureInfo.height;
int y1 = (y*height + height)/self.textureInfo.height;
q.bl.textureVertex = CGPointMake(x0, y0);
q.br.textureVertex = CGPointMake(x1, y0);
q.tl.textureVertex = CGPointMake(x0, y1);
q.tr.textureVertex = CGPointMake(x1, y1);
//add q to quads
}
}
The problem is I don't know how to add the quad "q" to the array "quads". Simple writing [quads addObject:q] doesn't work because the parameter should be an id not a TexturedQuad. I've seen examples of how to make an id from an int etc, but I don't know how to do it with an object like my TexturedQuad.
The essence of it is that you wrap your C struct in an Obj-C class. The Obj-C class to use is NSValue.
// assume ImaginaryNumber defined:
typedef struct {
float real;
float imaginary;
} ImaginaryNumber;
ImaginaryNumber miNumber;
miNumber.real = 1.1;
miNumber.imaginary = 1.41;
// encode using the type name
NSValue *miValue = [NSValue value: &miNumber withObjCType:#encode(ImaginaryNumber)];
ImaginaryNumber miNumber2;
[miValue getValue:&miNumber2];
See here for more information.
As #Bersaelor pointed out, if you need better performance use pure C or switch to Obj-C++ and use vectors instead of Obj-C objects.
An NSMutableArray takes any NSObject* but not just structs.
If you're serious about programming in Objective-C, take a look at some tutorials.
Furthermore, NSMutableArrays are meant for convenience, if your adding/deleting a lot of objects to that Array, use plain C-stacks.
Especially for your use-case that more low-level approach will get better performance.
Keep in mind, Objective-C(++) is just a superset of C(++), so you can use any C(++) code you are already familiar with.
When I wrote my game tactica for iOS, I switched to C-Code whenever I had to do heavy lifting (i.e. recursive AI-functions that get called hundreds of times per second).

Dynamically allocating length to an objective C static array

Hi I am relatively new to programming on iOS and using objective C. Recently I have come across an issue I cannot seem to solve, I am writing a OBJ model loader to use within my iOS programming. For this I use two arrays as below:
static CGFloat modelVertices[360*9]={};
static CGFloat modelColours[360*12]={};
As can be seen the length is currently allocated with a hard coded value of 360 (the number of faces in a particular model). Is there no way this can be dynamically allocated from a value that has been calculated after reading the OBJ file as is done below?
int numOfVertices = //whatever this is read from file;
static CGFloat modelColours[numOfVertices*12]={};
I have tried using NSMutable arrays but found these difficult to use as when it comes to actually drawing the mesh gathered I need to use this code:
-(void)render
{
// load arrays into the engine
glVertexPointer(vertexStride, GL_FLOAT, 0, vertexes);
glEnableClientState(GL_VERTEX_ARRAY);
glColorPointer(colorStride, GL_FLOAT, 0, colors);
glEnableClientState(GL_COLOR_ARRAY);
//render
glDrawArrays(renderStyle, 0, vertexCount);
}
As you can see the command glVertexPointer requires the values as a CGFloat array:
glVertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
You could use a c-style malloc to dynamically allocate space for the array.
int numOfVertices = //whatever this is read from file;
CGFloat *modelColours = (CGFloat *) malloc(sizeof(CGFloat) * numOfVertices);
When you declare a static variable, its size and initial value must be known at compile time. What you can do is declare the variable as a pointer instead of an array, the use malloc or calloc to allocate space for the array and store the result in your variable.
static CGFloat *modelColours = NULL;
int numOfVertices = //whatever this is read from file;
if(modelColours == NULL) {
modelColours = (CGFloat *)calloc(sizeof(CGFloat),numOfVertices*12);
}
I used calloc instead of malloc here because a static array would be filled with 0s by default, and this would ensure that the code was consistent.