convert struct to objective c array or class - ios

I m new for IOS. I have some source code for OS X and java. I was trying to convert to IOS.
In OS X, I have the following.
struct _NoteData {
int number; /** The Midi note number, used to determine the color */
WhiteNote *whitenote; /** The white note location to draw */
NoteDuration duration; /** The duration of the note */
BOOL leftside; /** Whether to draw note to the left or right of the stem */
int accid; /** Used to create the AccidSymbols for the chord */
};
typedef struct _NoteData NoteData;
#interface ChordSymbol : NSObject <MusicSymbol> {
_NoteData notedata[20];/** The notes to draw */
}
_NoteData is like an array and class here. number, whitenote,duration..are instance variable for _noteData.
I was trying to change struct to objective c class:
#interface _NoteData:NSObject{
#property NSInteger number_color;
#property WhiteNote *whitenote;
#property NoteDuration duration;
#property BOOL leftside;
#property NSInteger accid;
};
#interface ChordSymbol : NSObject <MusicSymbol> {
_NoteData notedata[20];/** The notes to draw */
}
In my .m file, it has
+(BOOL)notesOverlap:(_NoteData*)notedata withStart:(int)start andEnd:(int)end {
for (int i = start; i < end; i++) {
if (!notedata[i].leftside) {
return YES;
}
}
return NO;
}
!notedata[i] throw error expected method to read array element. I understand _NoteData is a class, not an array. What should I change?
In java:
private NoteData[] notedata;
NoteData is a class, and notedata is an array which store NoteData.
Same method in java
private static boolean NotesOverlap(NoteData[] notedata, int start, int end) {
for (int i = start; i < end; i++) {
if (!notedata[i].leftside) {
return true;
}
}
return false;
}
I feel all I need is to declare an array with _NoteData object. How can I do that?

Objective-C is a superset of C, so you can use C struct in Objective-C code. You can keep your code in the first paragraph. You need to move the function declaration in ChordSymbol class's header file.
+(BOOL)notesOverlap:(NoteData*)notedata withStart:(int)start andEnd:(int)end;
In another Objective-C class's implementation file, call the Class function like this.
NoteData y[] = {
{ .leftside = YES },
{ .leftside = YES },
{ .leftside = YES },
{ .leftside = YES }
};
BOOL result = [ChordSymbol notesOverlap:y withStart:0 andEnd:3];
NSLog(#"%d",result);
Edit
You can use NSArray for this purpose. You create an array and populate its data with NoteData objects.
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:20];
NoteData *data1 = [[NoteData alloc] init];
data1.number_color = 1;
[array addObject:data1];
Then you should change (_NoteData*)notedata to (NSArray*)array, and it should work.

Related

MQL4 Send objects array as function parameter

I had the function as a class member with an array of my custom object as a parameter:
class Stochastic { ... some class which sent into initializeStochastics method as param };
class StochasticInitializer {
public:
Properties *properties[8];
public:
StochasticInitializer(void) {
this.properties = ...
}
public:
void initializeStochastics(Stochastic& *stochastics[]) { // This param is my problem
for (int i = 0 ;i < ArraySize(properties); i++) {
if (properties[i].enabled) {
stochastics[i] = new Stochastic(properties[i]);
}
}
}
};
My errors:
'&' - comma expected
']' - declaration without type
']' - comma expected
'initializeStochastics' - wrong parameters count
'stochastics' - undeclared identifier
I take syntax from here, but perhaps it solution for MQL5.
Can I send an array of class instances as a method parameter in MQL4? If "yes" - how, if no - it answers too.
Everything works (almost works) just decide whether you are going to create an global array or with pointer access (need to delete it after you finish). Here is example of pointers. Also, please provide MCVE next time, because someone needs to write all that useless stuff like properties&stoch classes to make it testable.
class Properties
{
public:
bool enabled;
int periodK;
Properties(bool _enabled,int k):enabled(_enabled),periodK(k){}
~Properties(){}
};
class Stochastic
{
public:
int periodK;
Stochastic(){}
~Stochastic(){}
Stochastic(Properties *prop):periodK(prop.periodK){}
double get(const int shift,const int buffer=0)const{return iStochastic(_Symbol,0,periodK,3,3,MODE_SMA,STO_LOWHIGH,buffer,shift);}
};
class StochasticInitializer
{
public:
Properties *properties[8];
StochasticInitializer()
{
Deinit();
properties[0]=new Properties(true,5);
properties[1]=new Properties(true,13);
properties[2]=new Properties(true,14);
properties[3]=new Properties(true,15);
properties[4]=new Properties(true,16);
properties[5]=new Properties(true,17);
properties[6]=new Properties(true,18);
properties[7]=new Properties(false,19);
}
~StochasticInitializer(){Deinit();}
void Deinit(const int reason=0){ for(int i=0;i<ArraySize(properties);i++)delete(properties[i]); }
void initializeStochastics(Stochastic *&stochastics[])// THIS IS WHAT YOU NEED IN CASE OF POINTERS
{
for(int i=0;i<ArraySize(properties);i++)
{
if(properties[i].enabled)
{
stochastics[i]=new Stochastic(properties[i]);
}
}
}
};
StochasticInitializer initializer;
void OnTick()
{
Stochastic *array[8]; //THIS IS ARRAY OF POINTERS
initializer.initializeStochastics(array);
for(int i=0;i<ArraySize(array);i++)
{
printf("%i %s: %d %s",__LINE__,__FILE__,i,CheckPointer(array[i])==POINTER_INVALID ? "null" : (string)array[i].periodK);
}
for(int i=ArraySize(array)-1;i>=0;i--)delete(array[i]);//DELETING POINTERS
ExpertRemove();
}

How to check whether a protocol contains certain method programatically in Objective-C?

Is there any way to check whether a protocol contains certain method or whether a method belongs to certain protocol in Objective-C?
I don't think the redirected question is the same as mine. What I want is:
[MyProtocol containsSelector:#selector(MySelector)];
Or
[MySelector isMethodOfProtocol:#protocol(MyProtocol)];
See the Objective-C runtime functions
Protocol *objc_getProtocol(const char *name)
struct objc_method_description *protocol_copyMethodDescriptionList(Protocol *p, BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *outCount)
The documentation can, at the time of this writing, be found here.
If you know the name of the method, here is what you can do :
First set the delegate of the protocol.
Then, check if the method belongs to the protocol as this :
if ([something.delegate respondsToSelector:#selector(someMethodToCheck)])
Here is a small code snippet I am using right now (thanks to Avi's answer above):
- (BOOL)isSelector:(SEL)selector
ofProtocol:(Protocol *)protocol {
unsigned int outCount = 0;
struct objc_method_description *descriptions
= protocol_copyMethodDescriptionList(protocol,
YES,
YES,
&outCount);
for (unsigned int i = 0; i < outCount; ++i) {
if (descriptions[i].name == selector) {
free(descriptions);
return YES;
}
}
free(descriptions);
return NO;
}
You can move this to a category on NSObject too, if you use forwarding extensively.
Here is a function I found Apple using:
#import <objc/runtime.h>
BOOL MHFProtocolHasInstanceMethod(Protocol *protocol, SEL selector) {
struct objc_method_description desc;
desc = protocol_getMethodDescription(protocol, selector, NO, YES);
if(desc.name){
return YES;
}
desc = protocol_getMethodDescription(protocol, selector, YES, YES);
if(desc.name){
return YES;
}
return NO;
}
Use like this:
- (id)forwardingTargetForSelector:(SEL)aSelector{
if(MHFProtocolHasInstanceMethod(#protocol(UITableViewDelegate), aSelector)){
...

Property default values based on another property's value

In Realm,
Is it possible to set the default value of a persisted property, based on the value of another property?
For example. I have a name property that includes UpperCase/LowerCase/Accents/etc. I want to have a tokenizedName that transforms the name property into a more simple string (all undercase, no accents).
You could easily do this with derived properties:
class Person: Object {
var name: String {
get {
return _name
}
set {
_name = newValue
// perform tokenization...
tokenizedName = _name.lowercaseString
}
}
private dynamic var _name = ""
dynamic var tokenizedName = ""
override class func ignoredProperties() -> [String] { return ["name"] }
}
Here _name and tokenizedName are properties persisted in Realm, while name is ignored. Every time you read from name, you're just from its underlying storage. Every time you write to name, you set its backing storage and update the tokenized version.
Edit: In Objective-C
#interface Person : RLMObject
#property (nonatomic, copy) NSString *name;
#property NSString *_name;
#property NSString *tokenizedName;
#end
#implementation Person
- (NSString *)name {
return self._name;
}
- (void)setName:(NSString *)name {
self._name = name;
// perform tokenization...
self.tokenizedName = name.lowercaseString;
}
+ (NSArray<NSString *> *)ignoredProperties {
return #[#"name"];
}
#end

public private and protected in objective-c

Hi I am trying to learn Opps concept in Objective C but I know PHP so I took a program in which for public, private and protected mentioned bellow.
<?php
//Public properties and method can be inherited and can be accessed outside the class.
//private properties and method can not be inherited and can not be accessed outside the class.
//protected properties and method can be inherited but can not be accessed outside the class.
class one
{
var $a=20;
private $b=30;
protected $c=40;
}
class two extends one
{
function disp()
{
print $this->c;
echo "<br>";
}
}
$obj2=new two;
$obj2->disp(); //Inheritance
echo"<br>";
$obj1=new one;
print $obj1->c; //Outside the class
?>
So this I am trying to convert in Objective c code mentioned bellow.
#import <Foundation/Foundation.h>
#interface one : NSObject
{
#private int a;
#public int b;
#protected int c;
}
#property int a;
#property int b;
#property int c;
#end
#implementation one
#synthesize a,b,c;
int a=10;
int b=20;
int c=30;
#end
#interface two : one
-(void)setlocation;
#end
#implementation two
-(void)setlocation;
{
// NSLog(#"%d",a);
NSLog(#"%d",b);
// NSLog(#"%d",c);
}
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
// insert code here...
two *newtwo;
newtwo =[[two alloc]init];
//calling function
[newtwo setlocation];
}
return 0;
}
When I run the above code I am getting
2015-11-03 23:20:16.877 Access Specifier[3562:303] 0
Can some one resolve my problem.
This type of question has been asked before and there's a good explanation in the accepted answer for Private ivar in #interface or #implementation
In general I would recommend you avoid instance variables and use #property instead. Properties have the benefit of read-only/write controls, and free synthesized setters and getters (which if you're learning OOP concepts is a critical concept you should employ).
Properties are declared in the #interface part of an Obj-C file. For access control (according to the link) you have no public/private/protected keywords. All Obj-C methods (and by extension, properties) are public if they're defined in the .h file. If you want them "private" you define them in the the .m file using a class category:
//MyClass.m
#interface MyClass ()
#property(nonatomic, retain) NSString* myString;
#end
#implementation MyClass
#end

Best way to enum NSString

Im digging for ways to enum objc object such as NSString, I remember there a new feature in a version of Xcode4+ which offering a new way to enum , but not clearly. Anyone know that?
OK, I answered myself. Guess I make a mistake.
This is the new feature I mentioned above:
typedef enum Language : NSUInteger{
ObjectiveC,
Java,
Ruby,
Python,
Erlang
}Language;
It's just a new syntax for enum in Xcode 4.4, but I'm so foolish to think we can exchange "NSUInteger" to "NSString".
So here is the way I found that works:
http://longweekendmobile.com/2010/12/01/not-so-nasty-enums-in-objective-c/
// Place this in your .h file, outside the #interface block
typedef enum {
JPG,
PNG,
GIF,
PVR
} kImageType;
#define kImageTypeArray #"JPEG", #"PNG", #"GIF", #"PowerVR", nil
...
// Place this in the .m file, inside the #implementation block
// A method to convert an enum to string
-(NSString*) imageTypeEnumToString:(kImageType)enumVal
{
NSArray *imageTypeArray = [[NSArray alloc] initWithObjects:kImageTypeArray];
return [imageTypeArray objectAtIndex:enumVal];
}
// A method to retrieve the int value from the NSArray of NSStrings
-(kImageType) imageTypeStringToEnum:(NSString*)strVal
{
NSArray *imageTypeArray = [[NSArray alloc] initWithObjects:kImageTypeArray];
NSUInteger n = [imageTypeArray indexOfObject:strVal];
if(n < 1) n = JPG;
return (kImageType) n;
}
FYI. The original author of the second example code created a category for enum handling. Just the thing for adding to your very own NSArray class definition.
#interface NSArray (EnumExtensions)
- (NSString*) stringWithEnum: (NSUInteger) enumVal;
- (NSUInteger) enumFromString: (NSString*) strVal default: (NSUInteger) def;
- (NSUInteger) enumFromString: (NSString*) strVal;
#end
#implementation NSArray (EnumExtensions)
- (NSString*) stringWithEnum: (NSUInteger) enumVal
{
return [self objectAtIndex:enumVal];
}
- (NSUInteger) enumFromString: (NSString*) strVal default: (NSUInteger) def
{
NSUInteger n = [self indexOfObject:strVal];
if(n == NSNotFound) n = def;
return n;
}
- (NSUInteger) enumFromString: (NSString*) strVal
{
return [self enumFromString:strVal default:0];
}
#end
Alternative way to use struct:
extern const struct AMPlayerStateReadable
{
__unsafe_unretained NSString *ready;
__unsafe_unretained NSString *completed;
__unsafe_unretained NSString *playing;
__unsafe_unretained NSString *paused;
__unsafe_unretained NSString *broken;
} AMPlayerState;
const struct AMPlayerStateReadable AMPlayerState =
{
.ready = #"READY",
.completed = #"COMPLETE",
.playing = #"PLAYING",
.paused = #"PAUSED",
.broken = #"BROKEN"
};
Then you can use like this:
NSString *status = AMPlayerState.ready;
Easy to use, readable.
Would be nice if someone update/edit answer with advantages/disadvantages of this approach.
Recommended way from apple docs:
You use the NS_TYPED_ENUM to group constants with a raw value type that you specify. Use NS_TYPED_ENUM for sets of constants that can't logically have values added in a Swift extension, and use NS_TYPED_EXTENSIBLE_ENUM for sets of constants that can be expanded in an extension.
Apple docs
typedef NSString *MyEnum NS_TYPED_ENUM;
extern MyEnum const MyEnumFirstValue;
extern MyEnum const MyEnumSecondValue;
extern MyEnum const MyEnumThirdValue;
in the .h file. Define your strings in the .m file
MyEnum const MyEnumFirstValue = #"MyEnumFirstValue"
MyEnum const MyEnumSecondValue = #"MyEnumSecondValue";
MyEnum const MyEnumThirdValue = #"MyEnumThirdValue";
Works as expected in both Objective-C
- (void)methodWithMyEnum:(MyEnum)myEnum { }
and Swift
func method(_ myEnum: MyEnum) { }
This will be validated by compiler, so you won't mix up indices accidentally.
NSDictionary *stateStrings =
#{
#(MCSessionStateNotConnected) : #"MCSessionStateNotConnected",
#(MCSessionStateConnecting) : #"MCSessionStateConnecting",
#(MCSessionStateConnected) : #"MCSessionStateConnected",
};
NSString *stateString = [stateStrings objectForKey:#(state)];
<nbsp;>
var stateStrings: [MCSessionState: String] = [
MCSessionState.NotConnected : "MCSessionState.NotConnected",
MCSessionState.Connecting : "MCSessionState.Connecting",
MCSessionState.Connected : "MCSessionState.Connected"
]
var stateString = stateStrings[MCSessionState.Connected]
UPDATE: A more Swifty way is to extend the enum with CustomStringConvertible conformance. Also, this way the compiler will safeguard to implement every new addition to the underlying enum (whereas using arrays does not), as switch statements must be exhaustive.
extension MCSessionState: CustomStringConvertible {
public var description: String {
switch self {
case .notConnected:
return "MCSessionState.notConnected"
case .connecting:
return "MCSessionState.connecting"
case .connected:
return "MCSessionState.connected"
#unknown default:
return "Unknown"
}
}
}
// You can use it like this.
var stateString = MCSessionState.connected.description
// Or this.
var stateString = "\(MCSessionState.connected)"
Update in 2017
Recent down votes drew my attention, and I'd like to add that enum is really easy to work with String now:
enum HTTPMethod: String {
case GET, POST, PUT
}
HTTPMethod.GET.rawValue == "GET" // it's true
Original Answer
Unfortunately I ended up using:
#define HLCSRestMethodGet #"GET"
#define HLCSRestMethodPost #"POST"
#define HLCSRestMethodPut #"PUT"
#define HLCSRestMethodDelete #"DELETE"
typedef NSString* HLCSRestMethod;
I know this is not what OP asked, but writing actual code to implement enum seems to be an overkill to me. I would consider enum as a language feature (from C) and if I have to write code, I would come up with some better classes that does more than enum does.
Update
Swift version seems to be prettier, although the performance can never be as good.
struct LRest {
enum HTTPMethod: String {
case Get = "GET"
case Put = "PUT"
case Post = "POST"
case Delete = "DELETE"
}
struct method {
static let get = HTTPMethod.Get
static let put = HTTPMethod.Put
static let post = HTTPMethod.Post
static let delete = HTTPMethod.Delete
}
}
I think you are looking for the inline array function. eg
#[#"stringone",#"stringtwo",#"stringthree"];
if not, i'm not sure you can enum objects.
you could however have a static array of strings and have the enum reference object at index.
This is how I do it, although it's not perfect. I feel the switch mechanism could be improved... also not positive about hash-collision resistance, don't know what apple uses under the hood.
#define ElementProperty NSString *
#define __ElementPropertiesList #[#"backgroundColor", #"scale", #"alpha"]
#define epBackgroundColor __ElementPropertiesList[0]
#define epScale __ElementPropertiesList[1]
#define epAlpha __ElementPropertiesList[2]
#define switchElementProperty(__ep) switch(__ep.hash)
#define caseElementProperty(__ep) case(__ep.hash)
-(void)setValue:(id)value forElementProperty:(ElementProperty)ep;
[self setValue:#(1.5) forElementProperty:epScale];
//Compiler unfortunately won't warn you if you are missing a case
switchElementProperty(myProperty) {
caseElementProperty(epBackgroundColor):
NSLog(#"bg");
break;
caseElementProperty(epScale):
NSLog(#"s");
break;
caseElementProperty(epAlpha):
NSLog(#"a");
break;
}

Resources