#implementation MonthView {
DayView *dayViews[6][7];
}
Xcode does not complain about this code, but AppCode gives a warning:
Pointer to non-const type 'DayView * * const * ' with no explicit lifetime
My intention was to create a 6x7 block of DayView pointers that will be part of the memory layout of any MonthView instance.
Is this code doing what I want, and how can I fix this warning?
What you're attempting to do is valid, but if the comments above are correct and this is due to a bug in AppCode and the warning you receive throws a wrench into the works (such as when using -Werror) or it just bothers you to receive it, you can get around it by just allocating the array inside -init.
Fair warning: This code is off the top of my head and I don't guarantee it to work as written.
#implementation MonthView {
DayView ***dayViews;
}
#interface MonthView
- (id)init {
if ((self = [super init])) {
int i;
// do stuff here
// Create the array
dayViews = malloc(sizeof(id) * 6);
dayViews[0] = malloc(sizeof(DayView *) * 6 * 7);
for (i = 1; i < 6; i++) {
dayViews[i] = dayViews[0] + (i * 7);
}
}
return self;
}
#end
This code should produce a two-dimensional array that you can access as normal, while minimizing the number of calls to malloc needed.
Related
I'm developing an app in Objective-C/OSX (first try). I had a struct (NSDevice custom type) which need to be accessed as a public/extern variable to allow the different interface of the class to access it.
Here is the declaration in the header.
struct NSDevice{
LIBMTP_raw_device_t * usbrawdevice;
int numusbrawdevice;
uint32_t rawdeviceID;
LIBMTP_mtpdevice_t *device;
};
extern struct NSDevice *Device;
#interface DeviceManager : NSObject
- (void) openDevice;
- (void) closeDevice;
#end
and how I implement it in the source file
#import "DeviceManager.h"
struct NSDevice *Device = NULL;
#implementation DeviceManager
- (id)init{
self = [super init];
if(self){
NSLog(#"Init");
LIBMTP_Init();
Device->device = NULL;
Device->numusbrawdevice = 0;
Device->rawdeviceID = 0;
Device->usbrawdevice = NULL;
}
return self;
}
- (NSMtp_error) openDevice {
LIBMTP_error_number_t error = LIBMTP_ERROR_GENERAL;
NSLog(#"Opening Device");
error = LIBMTP_Detect_Raw_Devices(&Device->usbrawdevice, &Device->numusbrawdevice);
When trying to init the struct in the init interface, I got an EXC_BAD_ACCESS. Any idea ?
Can I use the "struct" or is there a better way in Objective-C ?
Thx
Seb, you need to allocate the space for Device.
Try doing this:
- (id)init{
self = [super init];
if(self){
NSLog(#"Init");
LIBMTP_Init();
Device = malloc(sizeof(NSDevice));
Device->device = NULL;
Device->numusbrawdevice = 0;
Device->rawdeviceID = 0;
Device->usbrawdevice = NULL;
}
return self;
}
and declare your structure like this:
typedef struct {
LIBMTP_raw_device_t * usbrawdevice;
int numusbrawdevice;
uint32_t rawdeviceID;
LIBMTP_mtpdevice_t *device;
} NSDevice;
Also, I highly recommend changing the name of NSDevice to SebDevice or something that doesn't start with NS as those prefix characters usually signify something built into the MacOS SDK and it's going to confuse anyone else who has to look at your code after you depart the project.
And one last thing, global variables like this shouldn't start with capital letters. In Objective-C, best practice is for variables to start with lower case letters or maybe a g (for global) or an underscore. Change Device to gDevice.
I wonder is there any drawbacks when use alloc/free with pure C array inside Objective-C class?
For example:
#import "CVPatternGrid.h"
#implementation CVPatternGrid
#synthesize row = _row;
#synthesize column = _column;
#synthesize count = _count;
#synthesize score = _score;
- (id)initWithRow:(NSInteger)row column:(NSInteger)column {
if (self = [super init]) {
_grid = [self allocateNewGrid:row column:column];
}
return self;
}
- (NSInteger)moveCount {
return _count;
}
- (bool**)allocateNewGrid:(NSInteger)row column:(NSInteger)column {
bool **p = malloc(row * sizeof(bool*));
for (int i = 0; i < row; ++i) {
p[i] = malloc(column * sizeof(bool));
}
return p;
}
- (void)generateNewGrid:(NSInteger)row column:(NSInteger)column {
[self freeGrid];
_grid = [self allocateNewGrid:row column:column];
_count = [self.algorithmDelegate generateGrid:_grid];
_score = _count * 100;
}
- (BOOL)isMarkedAtRow:(NSInteger)row column:(NSInteger)column {
return YES;
}
- (void)freeGrid {
for (int i = 0; i < _row; ++i) {
free(_grid[i]);
}
free(_grid);
}
- (void)dealloc {
[self freeGrid];
}
#end
It's perfectly normal to use a C array in an Obj-C class. There are no low level data types in Obj-C — every class, including NSArray, NSString, etc, is using primitive C types internally.
However you are doing a few things wrong:
Do not use #synthesize unless you need to. In this case you don't need it, so delete those lines of code.
Do not use _foo to access variables unless you need it, again in this case you don't need it in any of your use cases (except, arguably, in your init and dealloc methods. But I would argue it should not even be used there. Other people disagree with me). My rule is to only use _foo when I run into performance issues when using self.foo syntax. There are also edge case issues such as KVO where you might run into problems when using an accessor inside init/dealloc. In the real world I have never run into any of those edge cases in more than 10 years of writing Obj-C — I always use accessors, unless they're too slow.
Some implementation details about how to declare an #property of a C array: Objective-C. Property for C array
So, I have to add a functionality to an old .cpp file.It's huge. So rewriting it in Objective C is not an option. Instead, I have added the necessary functionality using Objective-C (because I need a lot of the NSDate/NSDateFormatter functions). It worked fine. BUT, when calling the getter (on my view controller) I get this error: EXC_BAD_ACCESS.
Here is a fragment of the code:
//.h file -----------------
// C/C++ headers
#import <Foundation/NSDate.h>
#import <Foundation/NSDateFormatter.h>
namespace MySpace {
class Session {
private:
// C++ stuff
NSDate * startTime;
public:
// C++ stuff
NSDate * getStartTime();
Session(NSDate * startTime );
};
}
// .cpp file -----------------
using namespace MySpace;
Session:Session (NSDate * startTime) {
// unrelated code
if (startTime == nil ){
startTime = [NSDate date];
}
setStartTime( startTime);
// unrelated code
}
void Session::setStartTime( NSDate * startTime){
this->startTime = [startTime copy];
}
NSDate * Session::getStartTime() {
return this->startTime; // here I get the EXC_BAD_ACCESS
}
The entire project is compiled as Objective-C++ and ARC enabled. I believe this issue is caused because the member 'startTime' is released by ARC, and, when I call the getter, it points to nil?
How may I solve this problem?
Thanks.
Try that:
NSDate * Session::getStartTime() {
if (this == NULL) return nil;
return this->startTime; // here I get the EXC_BAD_ACCESS
}
The change makes getStartTime immune to a NULL this pointer.
Does that helps? If so, somewhere, you are using a dangling Session* pointer.
Step 2
Not that. That then:
#interface MyNSDate: NSDate
#end
#implementation MyNSDate
- (id) init
{
self = [super init];
if ( self == nil ) return nil;
NSLog( #"MyNSDate %# initialized", self );
return self;
}
- (void) dealloc
{
// ARC: no super call
NSLog( #"MyNSDate %# deallocated", self );
}
#end
And replace the NSDate* in your class with MyNSDate. Check the messages, breakpoint in dealloc... You should be able to find out when the date is deallocated, appropriate or not, or rules out that hypothesis.
The other idea that crossed my mind is the missing copy construcoperators. If you are copying your Session between ARC and non-ARC compilation units, it may break. You shouldn't do that, but hey, it happens.
Session::Session( const Session& rhs )
{
this->startTime = [rhs.startTime copy];
}
Session& Session::operator=( const Session& rhs )
{
if ( this->startTime != rhs.startTime )
{
this->startTime = [rhs.startTime copy];
}
return *this;
}
I wanted to create 2 global arrays which can be updated during the run of the programme.In each update i add one element to zeroth position and deleted the last number
I created the arrays as....
In the .h file..........
//////////////
#interface Shared : NSObject{
NSMutableArray *x;
NSMutableArray *y;
}
#property (nonatomic,retain) NSMutableArray *x;
#property (nonatomic,retain) NSMutableArray *y;
+(Shared*)sharedInstance;
#end
In .m file
staticShared* sharedInstance;
#implementation Shared
#synthesize x;
#synthesize y;
+(Shared*)sharedInstance
{
if (!sharedInstance) {
sharedInstance=[[Sharedalloc]init];
}
returnsharedInstance;
}
-(Shared*)init
{
self = [superinit];
if(self)
{
x=[[NSMutableArrayalloc] init];
x=[NSMutableArrayarrayWithObjects:#"0",#"0",#"0",#"0",#"0",#"0",#"0",nil];
y=[[NSMutableArrayalloc] init];
y=[NSMutableArrayarrayWithObjects:#"0",#"0",#"0",#"0",#"0",#"0",nil];
}
returnself;
}
#end
Then i used to call them and re,ove and added elements using the following code....
[[shared sharedInstance].y removeLastObject];
[[shared sharedInstance].y insertObject:new_element atIndex:0];
[[shared sharedInstance].x removeLastObject];
[[shared sharedInstance].x insertObject:new_element atIndex:0];
In the mean time i call these values and calculate an arithmetic value using an expression.
This seems to work well. But it seems to be an inefficient way to handle floating point numbers which i store in it. As these arrays creates objects. Is there any easy method that i can create a global array containing specified amount of floating point numbers and update it during the run of the programm(array size is fixed) by deleting the last object, and call them back to do calculation?
Please help me!
EDIT 1
To sir deanWombourne
.................................
I implement as you instructed! Can you please go through this and help me to correct 2 errors i get.
IN the .h file
#interface Shared : NSObject{
#private
float input[7];
float output[6];
}
+(Shared*)sharedInstance;
-(void)addNewInput:(float)input1;
-(float *)input;
-(void)addNewOutput:(float)output1;
-(float *)output;
#end
in .m file............
#implementation Shared
-(id)init{
if((self =[superinit])){
for(int n=0; n<7 ;++n)
input[n]=0.00f;
for(int n=0; n<6 ;++n)
output[n]=0.00f;
}
returnself;
}
-(void)addNewInput:(float)input1{
input[0]=input[1];
input[1]=input[2];
input[2]=input[3];
input[3]=input[4];
input[4]=input[5];
input[5]=input[6];
input[6]=input1;
}
-(float *)input {
returninput;
}
-(void)addNewOutput:(float)output1{
output[0]=output[1];
output[1]=output[2];
output[2]=output[3];
output[3]=output[4];
output[4]=output[5];
input[5]=output1;
}
-(float *)output {
returnoutput;
}
#end
When calling it
float reading= (accel_reading)/(1.165969038*1e5f);
[[SharedsharedInstance] addNewInput:reading];
Problems i get
1. In the implementation, it says incomplete implementation (it's a warning not an error)
2. How can i used a for loop to fill array values or is this way ok?
Major problem i get,
When i call it as shown above, program stops running telling
Terminating application due to uncaught exception 'NSInvalidArgumentException', reason '+[SharedsharedInstance]: unrecognized selector sent to class 0x5780'
Please help me through this...............
Your code Smells (and I mean that in the nicest possible way!)
Using two parallel arrays and keeping in sync is a bad design pattern (and a performance hit in quite a few ways!). Especially as there is already a struct that handles storing an x and y at the same time - CGPoint).
You're solving the 'only objects go in arrays' problem by converting your float' primitives toNSString` objects, which is horrendously inefficient - take a look instead at the NSValue class, it's designed to put native C primitives into an object without expensive parsing operations :)
You might also want to look into malloc (and free etc) and deal with the whole problem at the C level - this will mean no objects at all and would be blindingly fast (at the cost of more complicated code).
Hope this helps, if you have any questions just add a comment to this answer :)
EDIT
If all you want to do is store 4 x and y values, then this is probably the easiest way to do it :
#interface Shared : NSObject {
#private
CGPoint points[4];
}
+(Shared *)sharedInstance;
- (void)addNewPoint:(CGPoint)point;
- (CGPoint *)points;
#end
#implementation
- (id)init {
if ((self = [super init])) {
// Start with 0,0 for all your points
for (int n = 0; n < 4; ++n)
points[n] = CGPointZero;
}
return self;
}
- (void)addNewPoint:(CGPoint)point {
// Just move all the points along one and add the new one to the end
// (yes, this could be done in a loop but there's not that much point for 4 points!)
points[0] = points[1];
points[1] = points[2];
points[2] = points[3];
points[3] = point;
}
- (CGPoint *)points {
return points;
}
#end
This gives you a method addNewPoint that removes the first point and adds the new point to the end of your array.
You also get the method points that returns the 4 points. Use it something like :
// To add a point
CGPoint newPoint = CGPointMake(100, 100);
[[Shared sharedInstance] addNewPoint:newPoint];
// To do something with the points (in this case, NSLog them)
CGPoint *points = [[Shared sharedInstance] points];
for (int n = 0; n < 4; ++n)
NSLog(#" Point %i : %#", n, NSStringFromCGPoint(points[n]));
EDIT #2
From your comments, you need two arrays, one with input data and one with output data. Try something like this :
#interface Shared : NSObject {
float inputs[4];
float outputs[5];
}
...
This will give you two arrays to read/write to - one called inputs and the other called outputs. Access them in pretty much the same way you did the ones in my first edit :
float *inputs = [[Shared sharedInstance] inputs];
for (int n = 0; n < 4; ++n)
NSLog(#" Input %i : %f", n, inputs[n]);
float *outputs = [[Shared sharedInstance] outputs];
for (int n = 0; n < 5; ++n)
NSLog(#" Output %i : %f", n, output[n]);
Would a linked list be overkill for what you're trying to achieve? It's not quite as simple as a static array of floats, but makes the removal of the last object and insertion of the zeroth object reasonably simple and fast.
If you want an array containing a specific number of Objects, you can use NSArray, which is static, opposed to NSMutableArray.
As for the array being Global, just implement a singleton class that contains the 2 arrays and provides the associated methods.
in Globals.h:
#interface Globals : NSObject
+ (Globals *) sharedGlobals;
#end
in Globals.m:
#implementation Globals
static Globals *sharedGlobals = nil;
+ (Globals *) sharedGlobals{
#synchronized(self){
if (sharedGlobals == nil){
sharedGlobals = [[self alloc] init];
}
}
return sharedGlobals;
}
you then can access the arrays (after you implemented them) with the following line:
[[Globals sharedGlobals] getArrayX];
Here is a sketch to get you going.
Your array size is fixed and only contains floating point numbers, start with a C array:
double x[] = {0, 0, 0, 0, 0, 0, 0};
double y[] = {0, 0, 0, 0, 0, 0};
The number of elements in these arrays can be calculated rather than hard-coded:
int xCount = sizeof(x)/sizeof(double);
int yCount = sizeof(y)/sizeof(double);
Now use these arrays as a circular buffer, declare a cursor and initialise:
int xCursor = 0;
The item at the front of the queue is at the cursor:
valueAtFrontOfQueue = x[xCursor]; // get the current front item
To remove the value at front and add a new one to the rear replace the value at the cursor with the new value and increment the cursor:
x[xCursor] = newValueForBackOfQueue; // replace it with new item for back of queue
xCursor = (xCursor + 1) % xCount; // and advance cursor using mod arithmetic to it cycles around
No wrapping doubles as objects, no dynamic allocation at all.
Wrap the above up as you see fit, maybe as a class, and you're done.
I'm currently learning Objective C and in the process I've made the silly little program below. The program compiles fine - however I get the warning "multiple methods named '-setName:' found".
I've only interfaced and implemented the method once.
What does this warning mean, and how do I correct it?
#import <Foundation/Foundation.h>
// these are the three yoga-exercises we can perform
typedef enum {
kCobra,
kUniversal,
kDog
} ExerciseName;
// translating our variables into human
NSString *nameExercise (ExerciseName nameExercise)
{
switch (nameExercise) {
case kCobra:
return #"Cobra Pose";
break;
case kUniversal:
return #"Universal Stretch";
break;
case kDog:
return #"Dog Pose";
break;
}
return #"no clue!";
} // nameExercise
#interface Exercise : NSObject
{
ExerciseName name;
}
-(void) setName: (ExerciseName) name;
-(void) exerciseDo;
#end
#implementation Exercise
-(void) setName: (ExerciseName) n {
name = n;
} // setName
-(void) exerciseDo {
NSLog(#"Exercise: %#",
nameExercise(name));
}
#end
void executeExercises(id exercises[], int count) {
int i;
for(i=0; i<count; i++) {
id exercise = exercises[i];
[exercise exerciseDo];
}
}
int main (int argc, const char * argv[]) {
id exercises[1];
exercises[0] = [Exercise new]; // initiating an object of class Exercise
[exercises[0] setName:kDog];
executeExercises(exercises, 1);
return 0;
} //main
the meaning of the message is that there are multiple selectors with the name setName: in the translation (that is, it is declared in at least on other place among all included headers). the compiler may choose the wrong selector (which can introduce undefined behavior).
you can typically correct the problem using one (or more) of the following approaches:
1) rename the method to a unique name: e.g. setExerciseName may be ok, if not used in other translations.
2) match the signature of the other selector. e.g. setName:(NSString *)name
3) use type safety:
Exercise * ex = [Exercise new];
[ex setName:kCobra];
4) cast the variable to the type: [(Exercise*)exercise setName:kCobra];
5) restore the type with a new variable: Exercise * ex = exercise;
since you have declared the var as an id, you have erased the type, and it means that the object may respond any visible selector. in general, you should not erase the type in this manner, except when truly necessary.
the best approach i see is a combination of 1 and 3:
[ex setExerciseName:kCobra];