typedef enum with CGSize? - ios

I have different size of pages. I want to use enum to select size of page. somethink like that
typedef NS_ENUM(CGSize, SizeType) {
MAXSIZE=CGSizeMake(640, 1196),
MIDIUMSIZE=CGSizeMake(320, 590),
MINSIZE=CGSizeMake(160, 280)
};
its possible? if not then whats the best way to do this i need this combine value in my whole application

An enum in C (and therefore in Objective-C) is a set of integer values, and that's why you cannot have CGSize values as members of it.
Instead, use constants. The best option is to look at what Apple does and mimic it.
If you take a look at CGGeometry.h you will find the definitions of various constants.
For instance, CGSizeZero is defined as
CG_EXTERN const CGSize CGSizeZero
CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
You can then do something similar by declaring a constant in your header
CG_EXTERN const CGSize kMaxSize;
and then defining it in the implementation
const CGSize kMaxSize = (CGSize){ 640, 1196 };
As a bonus you can also define a type synonym for CGSize, for instance:
typedef CGSize MySizeType;
and then use it for declaring both constants and variables, e.g.
CG_EXTERN const MySizeType kMaxSize;
...
#property (nonatomic) MySizeType aSize;
That does't change a bit from a technical point of view, but it's semantically nicer and it basically achieves the same purpose of a typedef enum (which is precisely providing a convenient synonym to int)

As per the other answers, enums are basically integers, not structs.
You can just #define the values in a constants file:
#define MAXSIZE CGSizeMake(640, 1196)
#define MIDIUMSIZE CGSizeMake(320, 590)
#define MINSIZE CGSizeMake(160, 280)
though you might want to rename them for easier mnemonics, readability and auto-completion purposes, like:
#define PURPOSE_SIZE_MAX ...
#define PURPOSE_SIZE_MED ...
...

You cannot.
The enum type is a C type and it must be integer types, each member must be the same type also.
You can use char, BOOL, int, uint, NSInteger and so on.
For constant floating point values, you will need to declare them one by one.
structs also need to be done one by one.

You can not use enum for this. In Objective C enum is inherited from C. So it is implicitly converted to int.

Related

Why does the compiler claim CGRect has no width member?

Note that I'm not trying to set the value in a CGRect. I'm mystified as to why the compiler is issuing this claim:
let widthFactor = 0.8
let oldWidth = wholeFrameView.frame.width
let newWidth = wholeFrameView.frame.width * widthFactor // Value of type '(CGRect) -> CGRect' has no member 'width'
let newWidth2 = wholeFrameView.frame.width * 0.8 // This is fine.
Width is a CGFloat where your multiplier is a Double. Explicitly declare the type of your multiplier:
let widthFactor: CGFloat = 0.8
All the dimensions of a CGRect are of type CGFloat, not Double, and because Swift is especially strict about types, you can't multiply a CGFloat by a Double.
The interesting thing though, is that both CGFloat and Double implement ExpressibleByFloatLiteral. This means that 0.8, a "float literal", can be interpreted as either a Double or a CGFloat. Without context, it's always a Double, because of how the compiler is designed. Note that this only applies to float literals like 3.14, 3e8 etc, and not to identifiers of variables.
So the expression wholeFrameView.frame.width * 0.8 is valid because the compiler sees that width is a CGFloat, so it treats 0.8 as a CGFloat as well. No problems.
On the other hand, when you declare the variable widthFactor, it is automatically given the type Double, because there aren't any more context on that line to suggest to the compiler that you want it to be any other type.
This can be fixed by directly telling the compiler that you want widthFactor to be a CGFloat:
let widthFactor: CGFloat = 0.8
Because, as others have noted, you can't multiply a Double and a CGFloat, the compiler doesn't know what you're intending.
So, instead of giving you an error about the frame property, which you currently think it's doing, it's actually making its best guess*, and giving you an error related to the frame method. No method method has a width property, so what it tells you is true.
*Of course, its best guess is not good enough, hence a human being coming here to ask a question about it. So please file a bug!
Stepping onto my soapbox: This confusion would be avoided if Apple hadn't named the method the thing it returns. The convention to prefix all such methods with get solves the problem. Some convention is important in any language with first-class functions, to disambiguate between properties and methods.
wholeFrameView.frame has no member width. Also, you need widthFactor to be of type CGFloat. Try:
let newWidth = wholeFrameView.frame.size.width * CGFloat(widthFactor)

Corresponding Swift Data types for Metal data types?

I am passing my metal kernel and shader functions a parameter structure. I can't find anywhere that specifies what Swift data types to use to match the data types in Metal.
I have done my best to guess what data types to use on the Swift side, but it seems to be very picky in what order I define the variables in my structs. Which leads me to believe that they are not aligned.
For instance, here are the data types I am using in Metal:
struct ComputeParameters {
bool yesNo;
int count;
float scale;
float2 point;
float4 color;
};
And here is my corresponding struct in Swift:
struct ComputeParameters {
var yesNo: Bool = false
var count: Int32 = 0
var scale: Float32 = 1.0
var point: float2 = float2(0.0, 0.0)
var color: float4 = float4(0.0, 0.0, 0.0, 1.0)
}
Here is a table of the datatypes I am using from above.
Metal _________ Swift
bool Bool
int Int32
float Float32
float2 float2
float4 float4
Are those correct? Is there somewhere the parameter datatypes are documented?
The size of the Int type in Swift depends on the target platform. It could be equal to Int32 or Int64, though these days it will almost always be Int64. So you should use the more explicit Int32 type to match Metal's 32-bit int type.
As of Swift 5, float2 and float4 are deprecated in favor of SIMD2<Float> and SIMD4<Float>, respectively. These correspond exactly with Metal's float2 and float4.
I believe the rest of your correspondences are correct.
However, it's probably not wise to define these structures in Swift in the first place. Swift gives you no guarantees regarding struct layout (padding, alignment, and member order). Therefore you could wind up with a layout mismatch between Swift and MSL (I haven't seen this happen, but the point is that it can).
The current guidance, I believe, is to define such structs in C/Objective-C instead and import them via a bridging header. That makes it more likely that memcpy-style copies of structs into Metal buffers will do the right thing. Always pay careful attention to size and alignment, especially since manual reordering of struct members can change the size and/or stride of the struct.

How to define several variable types in one .h file using `typedef NS_ENUM`

I have used typedef NS_ENUM to reorganise data constants in old code. Using an approach found here every typedef is declared in a single .h file that can be imported to any class in the project. Content of the .h file is wrapped in a message to the compiler. This works nicely for int variables.
MYCharacterType.h
#ifndef MYCharacterType_h
#define MYCharacterType_h
typedef NS_ENUM(NSInteger, MARGIN)
{
MARGIN_Top = 10,
MARGIN_Side = 10,
MARGIN_PanelBaseLine = 1
};
...
#endif /* SatGamEnumType_h */
But Xcode complains when I try to include float variables
“Non-Integral type ’NSNumber’ is an invalid underlying type’
e.g.
typedef NS_ENUM(NSNumber, LINE_WIDTH) {
LINE_WIDTH_Large = 1.5,
LINE_WIDTH_Medium = 1.0,
LINE_WIDTH_Small = 0.5,
LINE_WIDTH_Hairline = 0.25
};
I get the same message whether I use NSValue or NSNumber so I suspect typedef NS_ENUM is not the way to define float variables (or at least the way I am using it).
The approach in this answer would only allow me to do what I have already organised in one file but does not offer a way to reorganise float variables in the same file. Could someone please explain how to do this so all variables are defined in one .h file regardless of their type ? Thanks
SOLUTION
This was answered by rmaddy after I approached the question differently.
Defining different enums in one .h .. like just add it one file.
typedef NS_ENUM(NSInteger, MARGIN)
{
MARGIN_Top = 10,
MARGIN_Side = 10,
MARGIN_PanelBaseLine = 1
};
typedef NS_ENUM(long, ENUM_2)
{
ENUM_2_1 = 10,
ENUM_2_2 = 20,
ENUM_2_3 = 30,
};
typedef NS_ENUM(long, ENUM_3)
{
ENUM_3_1 = 10,
ENUM_3_2 = 20,
ENUM_3_3 = 30,
};
// And so on as many as you want
And your second question, Enums can only be of the integral data types like, int, long, long long, unsigned int, short etc... You can't use any Non-Integral types like float or double or not even any objective c types.
You can do enum mapping for float values like this https://stackoverflow.com/a/8867169/1825618

Separating values for UI from View

I'd like to create a NSObject subclass which would hold all my values for UIView.
Problem - what's the right way to do that?
Using "extern" and class method combination?
Using "extern" and #define combination?
Using only #define on class methods?
UI elements(e.g. UIColor) can't be initialized using "extern *const" method.
Writing a class methods for each value seems like too much.
Macros are plain(no coloring, etc.) and are declared only in header file.
Isn't there are better solution, which would hold all my ints,floats, colors in same place. And which is not a macro.
Why not macros?
For UIColor you can use:
#define RGBA_COLOR(r, g, b, a) [UIColor colorWithRed:(r/255.0) green:(g/255.0) blue:(b/255.0) alpha:a]
#define MY_GREEN_COLOR RGBA_COLOR(60, 192, 174, 1.0)
And then you can use MY_GREEN_COLOR without problems:
UIColor *color = MY_GREEN_COLOR;
And the same for int, floats and so on:
#define MY_INT 83
I usually have a "Globals.h" file with all this stuff.

How to define array of CGPoints within a struct definition?

I want to do this:
typedef struct
{
CGPoint vertices[];
NSUInteger vertexCount;
} Polygon;
But it says Field has incomplete type CGPoint [].
You need to do one of two things:
Declare the array to be a fixed size (probably not what you want)
Make it a pointer. But then you need to properly malloc and free the array as needed.
A better choice is to not use a struct and instead create a full class. Then you can add methods and properties as well as make memory management much easier. You are working in Objective-C. Take advantage of the Object Oriented aspects of the language. Add a method to calculate the circumference and area, etc. Put the logic where it belongs.
Set array size CGPoint vertices[count];
Don't you want a unique name for each element of your struct anyway? If you just want a bunch of CGPoint's in a numerical order, with the ability to count how many of them there are you'd be much better served by shoving them in an NSArray or NSMutableArray (stored as NSValue's of course)
The whole point of a struct would be to have easy access to the values by a descriptive name, ie:
typedef struct {
CGPoint helpfulAndDescriptiveNameOne;
CGPoint helpfulAndDescriptiveNameTwoWhichIsDifferentThanTheOtherName;
etc...
NSUInteger vertexCount;
}
For example, a CGRect is just a struct composed of four different CGFloats, each of which is descriptively and helpfully named:
typedef {
CGFloat x;
CGFloat y;
CGFloat width;
CGFloat height;
} CGRect;

Resources