I have a struct for a tile (all properties are previously-defined enums)
typedef struct {
ShapeType shape;
ColorType color;
PatternType pattern;
IconType icon;
} TileDefinition;
And I want to create another struct that holds 16 tiles, for a "board". Something like this:
typedef struct {
TileDefinition[16]
} BoardDefinition;
And then I want to be able to loop through that, like so:
for(int i=0;i<16;i++) {
TileDefinition tileDef = boardDef[i];
// Do something with tileDef
}
But obviously the setup for the BoardDefinition struct isn't working. How can I set that up? Where should I and shouldn't I use pointers?
Thanks
This is actually a C question.
This bit is fine:
typedef struct {
ShapeType shape;
ColorType color;
PatternType pattern;
IconType icon;
} TileDefinition;
Here, you need to declare BoardDefinition as:
enum { BoardDefinition_NTiles = 16 }; // << declare a constant for your ease of use
typedef struct {
TileDefinition tile[BoardDefinition_NTiles];
} BoardDefinition;
Then to loop through them:
// Given:
BoardDefinition boardDef;
for (size_t i = 0; i < BoardDefinition_NTiles; i++) {
TileDefinition* const tile = &boardDef.tile[i]; // << get a reference to a tile
// member access of the referenced tile:
tile->color.red = 1;
}
The version you wrote creates a copy of the tile:
for (size_t i = 0; i < BoardDefinition_NTiles; i++) {
TileDefinition tile = boardDef.tile[i]; // << creates a copy of the tile, local to the loop body
// member access of the copied tile:
tile.color.red = 1;
}
Option 1: Make BoardDefinition an Objective-C object where it can be set-up in the init method.
Option 2: Use (Objective-)C++ and provide a constructor for struct BoardDefinition.
Option 3: Keep with C and provide an initBoardDefinition(BoardDefinition *boardDef); function.
As trojanfoe suggest, these would be better as Objective-C objects, but if for some reason you don't wont to do that.
You probable want to declare an instance variable of type BoardDefinition in some class for example
#interface MyClass : NSObject
{
BoardDefinition definition;
}
Also you BoardDefinition is wrong it should be something like
typedef struct {
TileDefinition boardDef[16];
} BoardDefinition;
Your loop would then be something like
for(int i=0;i<16;i++) {
TileDefinition tileDef = definition.boardDef[i];
// Do something with tileDef
}
You don't need to use pointers put you could for the TileDefinition in the parent struct something like
typedef struct {
TileDefinition * tileDefinition;
NSUInteger count;
} BoardDefinition;
This way you can have a variable number of TileDefinition. In this case you would have to malloc the tileDefinition soemthing like the following for the class init method.
- (id)init
{
if( (self = [super init]) != nil )
{
definition.count = 16;
definition.tileDefinition = malloc( definition.count * sizeof(*definition.tileDefinition);
}
return self;
}
Related
I'm trying to create my own custom assert. However, I would like my assertion to automatically include all of the relevant variables. This seems really basic to me, and I've searched around for about an hour but I can't seem to find a way get access to all the relevant stack frame variables. Does anyone know how to get these variables?
FYI - I don't need to access the variables in the debugger, I need to access them programmatically. I would like to upload them along with the crash report to give me more information about the crash. I also know that I can print them out manually...that is exactly what I'm looking to avoid.
You are basically asking to re-invent a good sized chunk of the debugger.
Without symbols, there isn't anything you can interrogate to figure out the layout of the local frame. Even with symbols, it is quite likely that the optimizer will have stomped on any local variables as the optimizer will re-use stack slots at whim once it determines the variable is no longer needed within the frame.
Note that many crashes won't be able to be caught at all or, if caught, the frame within which they occurred will have long since been destroyed.
Since you mention that you are creating a custom assertion, it sounds like you really aren't looking to introspect crashes as much as dump a snap of the local frame when you programatically detect that things have gone off the rails. While there really isn't a means of automatically reporting on local stack state, you could do something like:
{ ... some function ....
... local variables ...
#define reportblock ^{ ... code that summarizes locals ... ; return summary; }
YourAssert( cond, "cond gone bad. summary: %#", reportblock());
}
Note that the #define ensures that each YourAssert() captures the state at the time of the assertion. Note also that the above might have a potentially significant impact on performance.
Note also that I just made that code up. It seems like it is worthy of investigation, but may prove non-viable for a number of reasons.
If you're willing to use Objective-C++, then this is definitely a possibility, as long as you are also willing to declare your variables differently, and understand that you will only be able to grab your own variables with this method.
Also note that it will increase your stack frame size with extra __stack_ variables, which could cause memory issues (although I doubt it, personally).
It won't work with certain constructs such as for-loops, but for 95% of cases, this should work for what you need:
#include <vector>
struct stack_variable;
static std::vector<const stack_variable *> stack_variables;
struct stack_variable {
void **_value;
const char *_name;
const char *_type;
const char *_file;
const char *_line;
private:
template<typename T>
stack_variable(const T& value, const char *type, const char *name, const char *file, const char *line) : _value((void **) &value), _type(type), _name(name), _file(file), _line(line) {
add(*this);
}
static inline void add(const stack_variable &var) {
stack_variables.push_back(static_cast<const stack_variable *>(&var));
}
static inline void remove(const stack_variable &var) {
for (auto it = stack_variables.begin(); it != stack_variables.end(); it++) {
if ((*it) == &var) {
stack_variables.erase(it);
return;
}
}
}
public:
template<typename T>
static inline stack_variable create(const T& value, const char *type, const char *name, const char *file, const char *line) {
return stack_variable(value, type, name, file, line);
}
~stack_variable() {
remove(*this);
}
void print() const {
// treat the value as a pointer
printf("%s:%s - %s %s = %p\n", _file, _line, _type, _name, *_value);
}
static void dump_vars() {
for (auto var : stack_variables) {
var->print();
}
}
};
#define __LINE_STR(LINE) #LINE
#define _LINE_STR(LINE) __LINE_STR(LINE)
#define LINE_STR _LINE_STR(__LINE__)
#define LOCAL_VAR(type, name, value)\
type name = value;\
stack_variable __stack_ ## name = stack_variable::create<type>(name, #type, #name, __FILE__, LINE_STR);\
(void) __stack_ ## name;
Example:
int temp() {
LOCAL_VAR(int, i_wont_show, 0);
return i_wont_show;
}
int main(){
LOCAL_VAR(long, l, 15);
LOCAL_VAR(int, x, 192);
LOCAL_VAR(short, y, 256);
temp();
l += 10;
stack_variable::dump_vars();
}
Output (note the junk extra bytes for the values smaller than sizeof(void *), there isn't much I can do about that):
/Users/rross/Documents/TestProj/TestProj/main.mm:672 - long l = 0x19
/Users/rross/Documents/TestProj/TestProj/main.mm:673 - int x = 0x5fbff8b8000000c0
/Users/rross/Documents/TestProj/TestProj/main.mm:674 - short y = 0xd000000010100
Threads will royally screw this up, however, so in a multithreaded environment this is (almost) worthless.
I decided to add this as a separate answer, as it uses the same approach as my other one, but this time with an all ObjC code. Unfortunately, you still have to re-declare all of your stack variables, just like before, but hopefully now it will work better with your existing code-base.
StackVariable.h:
#import <Foundation/Foundation.h>
#define LOCAL_VAR(p_type, p_name, p_value)\
p_type p_name = p_value;\
StackVariable *__stack_ ## p_name = [[StackVariable alloc] initWithPointer:&p_name\
size:sizeof(p_type)\
name:#p_name\
type:#p_type\
file:__FILE__\
line:__LINE__];\
(void) __stack_ ## p_name;
#interface StackVariable : NSObject
-(id) initWithPointer:(void *) ptr
size:(size_t) size
name:(const char *) name
type:(const char *) type
file:(const char *) file
line:(const int) line;
+(NSString *) dump;
#end
StackVariable.m:
#import "StackVariable.h"
static NSMutableArray *stackVariables;
#implementation StackVariable {
void *_ptr;
size_t _size;
const char *_name;
const char *_type;
const char *_file;
int _line;
}
-(id) initWithPointer:(void *)ptr size:(size_t)size name:(const char *)name type:(const char *)type file:(const char *)file line:(int)line
{
if (self = [super init]) {
if (stackVariables == nil) {
stackVariables = [NSMutableArray new];
}
_ptr = ptr;
_size = size;
_name = name;
_type = type;
_file = file;
_line = line;
[stackVariables addObject:[NSValue valueWithNonretainedObject:self]];
}
return self;
}
-(NSString *) description {
NSMutableString *result = [NSMutableString stringWithFormat:#"%s:%d - %s %s = { ", _file, _line, _type, _name];
const uint8_t *bytes = (const uint8 *) _ptr;
for (size_t i = 0; i < _size; i++) {
[result appendFormat:#"%02x ", bytes[i]];
}
[result appendString:#"}"];
return result;
}
+(NSString *) dump {
NSMutableString *result = [NSMutableString new];
for (NSValue *value in stackVariables) {
__weak StackVariable *var = [value nonretainedObjectValue];
[result appendString:[var description]];
[result appendString:#"\n"];
}
return result;
}
-(void) dealloc {
[stackVariables removeObject:[NSValue valueWithNonretainedObject:self]];
}
#end
Example:
#include "StackVariable.h"
int temp() {
LOCAL_VAR(int, i_wont_show, 0);
return i_wont_show;
}
int main(){
LOCAL_VAR(long, l, 15);
LOCAL_VAR(int, x, 192);
LOCAL_VAR(short, y, 256);
temp();
l += 10;
puts([[StackVariable dump] UTF8String]);
}
Output:
/Users/rross/Documents/TestProj/TestProj/main.m:676 - long l = { 19 00 00 00 00 00 00 00 }
/Users/rross/Documents/TestProj/TestProj/main.m:677 - int x = { c0 00 00 00 }
/Users/rross/Documents/TestProj/TestProj/main.m:678 - short y = { 00 01 }
This requires ARC (and all of it's magic) enabled for any file you want to test this in, or you will manually have to release the __stack_ variables, which won't be pretty.
However, it now gives you a hex dump of the variable (rather than the weird pointer one), and if you really tried hard enough (using __builtin_types_compatible), it could detect whether the result was an object, and print that.
Once again, threads will mess this up, but a simple way to fix that would be to create a NSDictionary of NSArrays, with a NSThread as the key. Makes it a bit slower, but let's be honest, if you're using this over the C++ version, you aren't going for performance.
Is there a way to assign values to enums during runtime in objective c?
I have several enums and want each of the enum to have certain value.
The values could be read from a xml file. Is there a way to do this?
Unfortunatley, #Binyamin is correct, you cannot do this with an enum. For this reason, I usually do the following in my projects:
// in .h
typedef int MyEnum;
struct {
MyEnum value1;
MyEnum value2;
MyEnum value3;
} MyEnumValues;
// in .m
__attribute__((constructor))
static void initMyEnum()
{
MyEnumValues.value1 = 10;
MyEnumValues.value2 = 75;
MyEnumValues.value3 = 46;
}
This also has the advantage of being able to iterate through the values, which is not possible with a normal enum:
int count = sizeof(MyEnumValues) / sizeof(MyEnum);
MyEnum *values = (MyEnum *) &MyEnumValues;
for (int i = 0; i < count; i++)
{
printf("Value %i is: %i\n", i, values[i]);
}
All in all, this is my preferred way to do enums in C.
No, enums information is erased at compile time.
I'm just learning Cocoa (coming from C#) and I'm getting a strange error for something that seems really simple. (charsSinceLastUpdate >= 36)
#import "CSMainController.h"
#implementation CSMainController
//global vars
int *charsSinceLastUpdate = 0;
NSString *myString = #"Hello world";
//
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
...
}
//other functions
- (void)textDidChange:(NSNotification *)aNotification {
NSLog(#"charsSinceLastUpdate=%i",charsSinceLastUpdate);
if (charsSinceLastUpdate>=36) { // <- THIS line returns the error: Comparison between pointer and integer
charsSinceLastUpdate=0;
[statusText setStringValue:#"Will save now!"];
} else {
charsSinceLastUpdate++;
[statusText setStringValue:#"Not saving"];
}
}
//my functions
- (void)showNetworkErrorAlert:(BOOL)showContinueWithoutSavingOption {
...
}
//
#end
Any help would be appreciated, thanks!
In your code, charsSinceLastUpdate is a pointer, you need to define it without the *:
int charsSinceLastUpdate = 0;
Unless, of course, you meant to define it as a pointer, in which case you'd need to use the dereference operator to retrieve the value that it's pointing to, like so:
if(*charsSinceLastUpdate >= 36) {
//...
}
I need to create an Objective-C method that converts an int into a byte array. In this instance, I can't use NSArray as a return type, it must be an UInt8 array. I've written a simple method to do this, but it has errors during compile and tells me that I have incompatible return types. Here is the code snippet. Any ideas?
- (UInt8[])ConvertToBytes:(int) i
{
UInt8 *retVal[4];
retVal[0] = i >> 24;
retVal[1] = i >> 16;
retVal[2] = i >> 8;
retVal[3] = i >> 0;
return retVal;
}
Return the value in a struct. You cannot return C-style arrays from C functions, and this also means that you cannot return them from Objective-C methods either. You can return a struct though, and structs are allowed arrays as members.
// in a header
typedef struct
{
UInt8 val[4];
} FourBytes;
// in source
- (FourBytes) convertToBytes:(int) i
{
FourBytes result = { i >> 24, i >> 16, i >> 8, i };
return result;
}
- (void) someMethod
{
FourBytes test = [someObject convertToBytes:0x12345678];
NSLog ("%d, %d, %d, %d", test.val[0], test.val[1], test.val[2], test.val[3]);
}
You can't return a local C array. You need to malloc(sizeof(UInt8) * 4), populate that, return the pointer and of course don't forget to free it when you're done.
Here's an example of how it would be written and used (just to emphasize the importance of freeing the memory you allocate):
+ (UInt8 *)convertToBytes:(int)i {
UInt8 *retVal = malloc(sizeof(UInt8) * 4);
retVal[0] = i >> 24;
retVal[1] = i >> 16;
retVal[2] = i >> 8;
retVal[3] = i >> 0;
return retVal;
}
- (void)someMethodUsingTheOtherOne {
int something = 900;
UInt8 *bytesOfInt = [[self class] convertToBytes:something];
someFunctionUsingTheBytes(bytesOFInt);
free(bytesOfInt);
}
(You'll probably notice that I also changed it to be a class method. Since it doesn't depend on any attributes of the instance, it makes more sense for it to be a class method or even just a function. But that doesn't have anything to do with how arrays and pointers work — I just like to use good coding style in examples.)
I have an object, and I want to list all the selectors to which it responds. It feels like this should be perfectly possible, but I'm having trouble finding the APIs.
This is a solution based on the runtime C functions:
class_copyMethodList returns a list of class methods given a Class object obtainable from an object.
#import <objc/runtime.h>
[..]
SomeClass * t = [[SomeClass alloc] init];
int i=0;
unsigned int mc = 0;
Method * mlist = class_copyMethodList(object_getClass(t), &mc);
NSLog(#"%d methods", mc);
for(i=0;i<mc;i++)
NSLog(#"Method no #%d: %s", i, sel_getName(method_getName(mlist[i])));
/* note mlist needs to be freed */
I think usually you'll want to do that in the console, instead of cluttering your code with debug code. This is how you can do that while debugging in lldb:
(Assuming an object t)
p int $num = 0;
expr Method *$m = (Method *)class_copyMethodList((Class)object_getClass(t), &$num);
expr for(int i=0;i<$num;i++) { (void)NSLog(#"%s",(char *)sel_getName((SEL)method_getName($m[i]))); }
This is also possible with Swift:
let obj = NSObject()
var mc: UInt32 = 0
let mcPointer = withUnsafeMutablePointer(&mc, { $0 })
let mlist = class_copyMethodList(object_getClass(obj), mcPointer)
print("\(mc) methods")
for i in 0...Int(mc) {
print(String(format: "Method #%d: %s", arguments: [i, sel_getName(method_getName(mlist[i]))]))
}
Output:
251 methods
Method #0: hashValue
Method #1: postNotificationWithDescription:
Method #2: okToNotifyFromThisThread
Method #3: fromNotifySafeThreadPerformSelector:withObject:
Method #4: allowSafePerformSelector
Method #5: disallowSafePerformSelector
...
Method #247: isProxy
Method #248: isMemberOfClass:
Method #249: superclass
Method #250: isFault
Method #251: <null selector>
Tested with the 6s simulator running iOS 9.2, Xcode Version 7.2 (7C68).
Taking inspiration from JAL's answer, in Swift you can do:
extension NSObject {
var __methods: [Selector] {
var methodCount: UInt32 = 0
guard
let methodList = class_copyMethodList(type(of: self), &methodCount),
methodCount != 0
else { return [] }
return (0 ..< Int(methodCount))
.flatMap({ method_getName(methodList[$0]) })
}
}
ARC realization
SomeClass *someClass = [[SomeClass alloc] init];
//List of all methods
unsigned int amountMethod = 0;
Method *methods = class_copyMethodList(someClass, &amountMethod);
for (unsigned int i = 0; i < amountMethod; i++) {
Method method = methods[i];
printf("\t method named:'%s' \n", sel_getName(method_getName(method)));
}
free(methods);
Something like this should work (just put it in the object you're curious about). For example if you have an object that's a delegate and want to know what 'hooks' are available this will print out messages to give you that clue:
-(BOOL) respondsToSelector:(SEL)aSelector {
printf("Selector: %s\n", [NSStringFromSelector(aSelector) UTF8String]);
return [super respondsToSelector:aSelector];
}
Note that I discovered this in the iPhone Developer's Cookbook so I can't take credit! For example output I get from a UIViewController that implements the protocols <UITableViewDelegate, UITableViewDataSource>:
Selector: tableView:numberOfRowsInSection:
Selector: tableView:cellForRowAtIndexPath:
Selector: numberOfSectionsInTableView:
Selector: tableView:titleForHeaderInSection:
Selector: tableView:titleForFooterInSection:
Selector: tableView:commitEditingStyle:forRowAtIndexPath:
Selector: sectionIndexTitlesForTableView:
Selector: tableView:sectionForSectionIndexTitle:atIndex:
...
...
etc.,etc.
If you want to also get the selectors for the super classes you can loop through like this:
Class c = [myObject class];
while (c != nil) {
int i = 0;
unsigned int mc = 0;
Method* mlist = class_copyMethodList(c, &mc);
NSLog(#"%d methods for %#", mc, c);
for(i = 0; i < mc; i++) {
const char* selName = sel_getName(method_getName(mlist[i]));
NSLog(#"Method #%d: %s", i, selName);
}
free(mlist);
c = [c superclass];
}