I'm trying to use the PImpl idiom to use the <vector> libray in my Objective-C project.
I have managed to implement it, but it only for the Int type as you can see in my .h and .mm file.
file.h
#import <Foundation/Foundation.h>
struct Vector_impl;
#interface MM_Matrix : NSObject
{
struct Vector_impl *MMVec;
}
#property unsigned rows, columns;
- (MM_Matrix *) initwith:(int) n and: (int) m;
- (long) size: (int) n;
file.mm
#import "MM_Matrix.h"
#include <vector>
struct Vector_impl
{
std::vector<std::vector<int>> matrix;
};
#implementation MM_Matrix : NSObject
- (MM_Matrix *) initwith:(int) n and:(int)m
{
[self setRows:n];
[self setColumns:m];
MMVec = new Vector_impl;
MMVec->matrix.resize(n);
for (int i=0; i<n; i++) {
MMVec->matrix[i].resize(m, 0);
}
return self;
}
- (long) size: (int) n
{
return MMVec->matrix[n].size();
}
#end
I would like to implement a generic type (template maybe?) as you would do in the <vector> library, but I have no idea how to achieve that.
Assuming that you want to template std::vector<std::vector<int>>: there are two possibilities:
Use a weak type, e.g. void* and take care of conversion inside the class.
Implement an interface for every type you want to support.
For the second option it is enough to instantiate the template class for every type, so that the compiler knows which types are used.
Also have a look at this related question: pimpl for a templated class.
Related
I'm trying to learn objective C and I'm looking through some simple code to figure it out. Here's an example of a header file:
#import <Foundation/Foundation.h>
#class XYPoint;
#interface Rectangle: NSObject
{
int width;
int height;
XYPoint *origin;
}
#property int width, height;
-(XYPoint *) origin;
-(void) setOrigin: (XYPoint *) pt;
-(void) setWidth: (int) w andHeight: (int) h;
-(int) area;
-(int) perimeter;
#end
Can anyone explain the meaning of the line "#property int width, height;"? Thanks!
The property syntax lets you declare a combination of a getter and a setter in a short syntax. In your code, the declaration creates four methods:
-(int) width;
-(void)setWidth:(int)val;
-(int) height;
-(void)setHeight:(int)val;
There is probably an implementation, too, which ties these methods to their "backing variables" with names width and height defined above; there may also be a #synthesize directive in the .m file.
In the current version of Objective-C the declaration of backing variables is unnecessary: all properties are synthesized by default, but you can provide your own implementations if you wish.
Properties support an alternative way of invoking getter and setter methods in Objective-C: in addition to the standard
int h = [point height];
[point setWidth:123];
you can write
int h = point.height;
point.width = 123;
It is not necessary to declare properties to use the dot syntax: you can call any value-returning method with no arguments or a setter method with a single argument using dot syntax.
It is just a way for other classes to refer to the private iVars declared between { and }.
Basically, it will create a getter and a setter, that, for primitive types like int will look like this:
- (int)width
{
return width;
}
- (void)setWidth:(int)width
{
_width = width;
}
And you can override these 2 methods if you want.
According to the conventions, the underlying instance variables should be prefixed with "_":
#interface Rectangle: NSObject
{
int _width;
int _height;
XYPoint *_origin;
}
If you do not declare them, the compiler does that for you, but be careful, in case you override both the getter and the setter, you need to add this kind of statements in the ".m" file:
#synthesize width = _width;
because in that case the compiler will not generate the "_width" ivar on your behalf.
I'm new to Objective-C and trying to figure out enums. Is there a way to scope an enum to a class so that the values could be used by another class? Something like this:
#interface ClassA {
typedef enum {
ACCEPTED,
REJECTED
} ClassAStatus;
}
#end
#interface ClassB {
typedef enum {
ACCEPTED,
REJECTED
} ClassBStatus;
}
#end
Though that does not work, obviously. Or is there a better way to do enums altogether?
Edit: I guess my wording wasn't clear, but I'm not asking how to declare enums. I'm aware that putting them at the top of the file works. I'm asking if there's a way to scope them so the values aren't global to the entire file.
You have to prefix your public enums. Simply put the enum definition in the header of your class.
// ClassA.h
typedef enum {
ClassAStatusAccepted,
ClassAStatusRejected
} ClassAStatus;
#interface ClassA {
ClassAStatus status;
}
#end
// ClassB.h
typedef enum {
ClassBStatusAccepted,
ClassBStatusRejected
} ClassBStatus;
#interface ClassB {
ClassBStatus status;
}
#end
This is how Apple does it.
Or you could use the new style:
// UIView.h
typedef NS_ENUM(NSInteger, UIViewAnimationCurve) {
UIViewAnimationCurveEaseInOut, // slow at beginning and end
UIViewAnimationCurveEaseIn, // slow at beginning
UIViewAnimationCurveEaseOut, // slow at end
UIViewAnimationCurveLinear
};
Just put the enum right at the top of your .h, like Apple does in UITableView.h, for example:
//
// UITableView.h
// UIKit
//
// Copyright (c) 2005-2012, Apple Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>
#import <UIKit/UIScrollView.h>
#import <UIKit/UISwipeGestureRecognizer.h>
#import <UIKit/UITableViewCell.h>
#import <UIKit/UIKitDefines.h>
typedef NS_ENUM(NSInteger, UITableViewStyle) {
UITableViewStylePlain, // regular table view
UITableViewStyleGrouped // preferences style table view
};
typedef NS_ENUM(NSInteger, UITableViewScrollPosition) {
UITableViewScrollPositionNone,
UITableViewScrollPositionTop,
UITableViewScrollPositionMiddle,
UITableViewScrollPositionBottom
}; // scroll so row of interest is completely visible at top/center/bottom of view
typedef NS_ENUM(NSInteger, UITableViewRowAnimation) {
UITableViewRowAnimationFade,
UITableViewRowAnimationRight, // slide in from right (or out to right)
UITableViewRowAnimationLeft,
UITableViewRowAnimationTop,
UITableViewRowAnimationBottom,
UITableViewRowAnimationNone, // available in iOS 3.0
UITableViewRowAnimationMiddle, // available in iOS 3.2. attempts to keep cell centered in the space it will/did occupy
UITableViewRowAnimationAutomatic = 100 // available in iOS 5.0. chooses an appropriate animation style for you
};
You probably recognize some of these name, but you may not have been aware they were actually apart of a public enum in Apple's header files.
Just want to add to #DrummerB's answer that I usually write like this. The namespace in camelCase, and then the constant in upper case.
typedef enum {
ClassAStatus_ACCEPTED,
ClassAStatus_REJECTED
} ClassAStatus;
I'm really confused with this problem. What I need to do is use some obj-c runtime feature in my project. Here is simple code in my .m file:
#import "Base.h"
#import <objc/runtime.h>
#implementation Base
- (void)someMethod {
NSUInteger numberMethods = 0;
Method *classMethods = class_copyMethodList([self class], &numberMethods);
for (int i = 0; i < numberMethods; i ++) {
classMethods[i]->method_name; //incomplete definition of type "struct objc_method"
}
#end
I got the following error: incomplete definition of type "struct objc_method". After some inspecting objc/runtime.h file I found something like this:
some code...
typedef struct objc_method *Method;
...some code...
struct objc_method {
SEL method_name OBJC2_UNAVAILABLE;
char *method_types OBJC2_UNAVAILABLE;
IMP method_imp OBJC2_UNAVAILABLE;
}
Is this something like forward declaration problem, or something else?
In addition to Martin answer, you should use functions like method_getName to retrieve the name of the method classMethods[i].
This is much more portable (especially these fields in the structure no longer exists since Objective-C 2.0 as the macro suggests) and will avoid problems like the one you have when the Runtime evolves.
These members cannot be accessed!
OBJC2_UNAVAILABLE macro indicates that a member is not available and only provides some insight into the structure.
I've read many things about enum types in objective-c, and I see there is many ways to define them. But I don't see the right way (if there is one) to define an enum that can be called with CARS.ROLLSROYCE and that cannot be used only with ROLLSROYCE in the code.
So I can define ROLLSROYCE in the CARS enum and also in the BEAUTIFULCARS enum.
Do you know the way to define such an enum ?
You are trying to implement namespaces for your Enums in Objective-C. What you're asking for is a lot of elbow grease in Objective-C. You are probably best-off using C++ for this, since it is easy and afaik fully supported in any iOS or Cocoa application. You'll have to rename the files that #import your C++ code to .mm files instead of .m files, and the C++ compiler can be trickier than the Objective-C one. Going this route you'll create a header file like Enums.h.
// Enums.h
namespace CARS
{
enum CARS
{
ROLLSROYCE
};
}
namespace BEAUTIFULCARS
{
enum BEAUTIFULCARS
{
ROLLSROYCE = 45
};
}
And in your .mm sourcefile
#import "Enums.h"
-(void)printEnumvals
{
NSLog(#"CARS %d BEAUTIFULCARS %d",
CARS::ROLLSROYCE,
BEAUTIFULCARS::ROLLSROYCE);
}
If you want to avoid using C++ for this solution, there's a lot more elbow grease, bookkeeping, and opportunity for error. You'll need a header and a source file for this.
// CARS.h
#interface BEAUTIFULCARS : NSObject
{
enum
{
BEAUTIFULCARS_ROLLSROYCE = 45
} BEAUTIFULCARS;
}
#end
#interface CARS : NSObject
{
enum
{
CARS_ROLLSROYCE
} CARS;
}
#end
// CARS.m
#implementation BEAUTIFULCARS
+(NSInteger)ROLLSROYCE{ return BEAUTIFULCARS_ROLLSROYCE; }
#end
#implementation CARS
+(NSInteger)ROLLSROYCE{ return CARS_ROLLSROYCE; }
#end
Your .m source is almost the same:
#import "CARS.h"
-(void)printEnumvals
{
NSLog(#"CARS %d BEAUTIFULCARS %d",
CARS.ROLLSROYCE,
BEAUTIFULCARS.ROLLSROYCE);
}
Objective-C does not manage scope in the same way that most other OO languages do. Interfaces define the properties and messages that an object that interface supports, but don't support protection levels like public or private. When you define an enum in an #interface, that enum ends up in global scope.
For my case, I didn't want to use C++ namespaces or write redundant Objective-C classes for such a simple case, so I fallen back to the C.
// Enum.h
typedef struct
{
const int ROLLSROYCE;
} _CARS;
typedef struct
{
const int ROLLSROYCE;
} _BEAUTIFULCARS;
extern const _CARS CARS;
extern const _BEAUTIFULCARS BEAUTIFULCARS;
And then in Enum.m, define values
// Enum.m
#import "Enum.h"
const _CARS CARS = {0};// 0 is to be assigned to ROLLSROYCE field in struct
const _BEAUTIFULCARS BEAUTIFULCARS = {1}; // same but with 1
And finally, in your "main" code
#import "Enum.h"
// Some method
{
NSLog(#"I can refer to CARS.ROLLSROYCE = %d and BEAUTIFULCARS.ROLLSROYCE = %d", CARS.ROLLSROYCE, BEAUTIFULCARS.ROLLSROYCE);
}
Which will produce this output:
I can refer to CARS.ROLLSROYCE = 0 and BEAUTIFULCARS.ROLLSROYCE = 1
How do you initialise a constant in a header file?
For example:
#interface MyClass : NSObject {
const int foo;
}
#implementation MyClass
-(id)init:{?????;}
For "public" constants, you declare it as extern in your header file (.h) and initialize it in your implementation file (.m).
// File.h
extern int const foo;
then
// File.m
int const foo = 42;
Consider using enum if it's not just one, but multiple constants belonging together
Objective C classes do not support constants as members. You can't create a constant the way you want.
The closest way to declare a constant associated with a class is to define a class method that returns it. You can also use extern to access constants directly. Both are demonstrated below:
// header
extern const int MY_CONSTANT;
#interface Foo
{
}
+(int) fooConstant;
#end
// implementation
const int MY_CONSTANT = 23;
static const int FOO_CONST = 34;
#implementation Foo
+(int) fooConstant
{
return FOO_CONST; // You could also return 34 directly with no static constant
}
#end
An advantage of the class method version is that it can be extended to provide constant objects quite easily. You can use extern objects, nut you have to initialise them in an initialize method (unless they are strings). So you will often see the following pattern:
// header
#interface Foo
{
}
+(Foo*) fooConstant;
#end
// implementation
#implementation Foo
+(Foo*) fooConstant
{
static Foo* theConstant = nil;
if (theConstant == nil)
{
theConstant = [[Foo alloc] initWithStuff];
}
return theConstant;
}
#end
A simple way for value type constants like integers is to use the enum hack as hinted by unbeli.
// File.h
enum {
SKFoo = 1,
SKBar = 42,
};
One advantage to this over using extern is that it's all resolved at compile time so there no memory is needed to hold the variables.
Another method is to use static const which is what was to replace the enum hack in C/C++.
// File.h
static const int SKFoo = 1;
static const int SKBar = 42;
A quick scan through Apple's headers shows that the enum hack method appears to be the preferred way of doing this in Objective-C and I actually find it cleaner and use it myself.
Also, if you are creating groups of options you should consider using NS_ENUM to create a typesafe constants.
// File.h
typedef NS_ENUM(NSInteger, SKContants) {
SKFoo = 1,
SKBar = 42,
};
More info on NS_ENUM and it's cousin NS_OPTIONS is available at NSHipster.