regular expression to read the string between <title> and </title> - iphone

I hope to read the contents between and in a html string.
I think it should be in objective-c
#"<title([\\s\\S]*)</title>"
below are the codes that rewrited for regular expression
//source of NSStringCategory.h
#import <Foundation/Foundation.h>
#import <regex.h>
#interface NSStringCategory:NSObject
{
regex_t preg;
}
-(id)initWithPattern:(NSString *)pattern options:(int)options;
-(void)dealloc;
-(BOOL)matchesString:(NSString *)string;
-(NSString *)matchedSubstringOfString:(NSString *)string;
-(NSArray *)capturedSubstringsOfString:(NSString *)string;
+(NSStringCategory *)regexWithPattern:(NSString *)pattern options:(int)options;
+(NSStringCategory *)regexWithPattern:(NSString *)pattern;
+(NSString *)null;
+(void)initialize;
#end
#interface NSString (NSStringCategory)
-(BOOL)matchedByPattern:(NSString *)pattern options:(int)options;
-(BOOL)matchedByPattern:(NSString *)pattern;
-(NSString *)substringMatchedByPattern:(NSString *)pattern options:(int)options;
-(NSString *)substringMatchedByPattern:(NSString *)pattern;
-(NSArray *)substringsCapturedByPattern:(NSString *)pattern options:(int)options;
-(NSArray *)substringsCapturedByPattern:(NSString *)pattern;
-(NSString *)escapedPattern;
#end
and .m file
#import "NSStringCategory.h"
static NSString *nullstring=nil;
#implementation NSStringCategory
-(id)initWithPattern:(NSString *)pattern options:(int)options
{
if(self=[super init])
{
int err=regcomp(&preg,[pattern UTF8String],options|REG_EXTENDED);
if(err)
{
char errbuf[256];
regerror(err,&preg,errbuf,sizeof(errbuf));
[NSException raise:#"CSRegexException"
format:#"Could not compile regex \"%#\": %s",pattern,errbuf];
}
}
return self;
}
-(void)dealloc
{
regfree(&preg);
[super dealloc];
}
-(BOOL)matchesString:(NSString *)string
{
if(regexec(&preg,[string UTF8String],0,NULL,0)==0) return YES;
return NO;
}
-(NSString *)matchedSubstringOfString:(NSString *)string
{
const char *cstr=[string UTF8String];
regmatch_t match;
if(regexec(&preg,cstr,1,&match,0)==0)
{
return [[[NSString alloc] initWithBytes:cstr+match.rm_so
length:match.rm_eo-match.rm_so encoding:NSUTF8StringEncoding] autorelease];
}
return nil;
}
-(NSArray *)capturedSubstringsOfString:(NSString *)string
{
const char *cstr=[string UTF8String];
int num=preg.re_nsub+1;
regmatch_t *matches=calloc(sizeof(regmatch_t),num);
if(regexec(&preg,cstr,num,matches,0)==0)
{
NSMutableArray *array=[NSMutableArray arrayWithCapacity:num];
int i;
for(i=0;i<num;i++)
{
NSString *str;
if(matches[i].rm_so==-1&&matches[i].rm_eo==-1) str=nullstring;
else str=[[[NSString alloc] initWithBytes:cstr+matches[i].rm_so
length:matches[i].rm_eo-matches[i].rm_so encoding:NSUTF8StringEncoding] autorelease];
[array addObject:str];
}
free(matches);
return [NSArray arrayWithArray:array];
}
free(matches);
return nil;
}
+(NSStringCategory *)regexWithPattern:(NSString *)pattern options:(int)options
{ return [[[NSStringCategory alloc] initWithPattern:pattern options:options] autorelease]; }
+(NSStringCategory *)regexWithPattern:(NSString *)pattern
{ return [[[NSStringCategory alloc] initWithPattern:pattern options:0] autorelease]; }
+(NSString *)null { return nullstring; }
+(void)initialize
{
if(!nullstring) nullstring=[[NSString alloc] initWithString:#""];
}
#end
#implementation NSString (NSStringCategory)
-(BOOL)matchedByPattern:(NSString *)pattern options:(int)options
{
NSStringCategory *re=[NSStringCategory regexWithPattern:pattern options:options|REG_NOSUB];
return [re matchesString:self];
}
-(BOOL)matchedByPattern:(NSString *)pattern
{ return [self matchedByPattern:pattern options:0]; }
-(NSString *)substringMatchedByPattern:(NSString *)pattern options:(int)options
{
NSStringCategory *re=[NSStringCategory regexWithPattern:pattern options:options];
return [re matchedSubstringOfString:self];
}
-(NSString *)substringMatchedByPattern:(NSString *)pattern
{ return [self substringMatchedByPattern:pattern options:0]; }
-(NSArray *)substringsCapturedByPattern:(NSString *)pattern options:(int)options
{
NSStringCategory *re=[NSStringCategory regexWithPattern:pattern options:options];
return [re capturedSubstringsOfString:self];
}
-(NSArray *)substringsCapturedByPattern:(NSString *)pattern
{ return [self substringsCapturedByPattern:pattern options:0]; }
-(NSString *)escapedPattern
{
int len=[self length];
NSMutableString *escaped=[NSMutableString stringWithCapacity:len];
for(int i=0;i<len;i++)
{
unichar c=[self characterAtIndex:i];
if(c=='^'||c=='.'||c=='['||c=='$'||c=='('||c==')'
||c=='|'||c=='*'||c=='+'||c=='?'||c=='{'||c=='\\') [escaped appendFormat:#"\\%C",c];
else [escaped appendFormat:#"%C",c];
}
return [NSString stringWithString:escaped];
}
#end
I use the codes below to get the string between "" and ""
NSStringCategory *a=[[NSStringCategory alloc] initWithPattern:#"<title([\s\S]*)</title>" options:0];//
Unfortunately [a matchedSubstringOfString:response]] always returns nil
I do not if the regular expression is wrong or any other reason.
Welcome any comment
Thanks
interdev

(Preliminary warning: you can't parse HTML correctly with Regex.)
You are using regex.h, which provides POSIX regular expression (ERE in your case). They do not support all of the PCRE syntax such as \s and \S (and [\s\S] is useless anyway — it matches anything).
Probably you should use
initWithPattern:#"<title[^>]*>([^<]*)</title>" options:REG_ICASE

<title[^>]*>\([^<]*\)</title> should do the trick.

For this specific case, I might try instantiating a WebDocumentRepresentation object from the /System/Library/Frameworks/WebKit framework.
You could set the data source for the WebDocumentRepresentation object to the HTML page you were interested in, and then use the object's title method to return the title.
Here's the Mac OSX Reference Library document on the object.

Related

Compare String Url with a String value

How can I search a string url for a string value?
String url:
http://localHost:8070/serviceCase=ActiveService
http://localHost:8070/serviceCase=KoplService
String Value is:
ActiveService
I need to print the urls that do have "ActiveService"!
You could probably do something like this(if your url really is a string):
if ([url rangeOfString:value].location == NSNotFound){
dosomething
} else {
doSomethingElse
}
NSString *url = #"http://localHost:8070/serviceCase=ActiveService";
if ([url rangeOfString:#"ActiveService"].location != NSNotFound) {
NSLog(#"URL has the string");
}
I recommend below NSString Category.
NSString+Extend.h
#import <Foundation/Foundation.h>
#interface NSString (Extend)
- (BOOL)containsString:(NSString *)aString ignoringCase:(BOOL)flag;
- (BOOL)containsString:(NSString *)aString;
#end
NSString+Extend.m
#import "NSString+Extend.h"
#implementation NSString (Extend)
- (BOOL)containsString:(NSString *)aString
{
return [self containsString:aString ignoringCase:NO];
}
- (BOOL)containsString:(NSString *)aString ignoringCase:(BOOL)flag
{
unsigned mask = (flag ? NSCaseInsensitiveSearch : 0);
return [self rangeOfString:aString options:mask].length > 0;
}
#end
#import "NSString+Extend.h"
NSString *url = #"http://localHost:8070/serviceCase=ActiveService";
NSString *findString = #"ActiveService";
BOOL isContains = [url containsString:findString];
if(isContains)
{
//do stuff
}
else
{
//do stuff
}
if([string hasSuffix:#"ActiveService"]) {
// Do your stuff
}

What alternatives to a switch statement could I use to update my UITableViewCells? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Alternative to switch statement in objective C
I have json data from an url which I display in the table cell using a switch statement. Since I have only 6 cells, I had used a switch statement but I am curious to know if there is any other method in place of switch statement to do so.
switch(indexPath.row)
{
case 0 :
cell.textLabel.text = [NSString stringWithFormat:#"%# %#",[dictionary valueForKey:#"firstname"],
[dictionary valueForKey:#"lastname"]];
break;
case 1:
cell.textLabel.text = [NSString stringWithFormat:#"%# : %#",#"Address",[dictionary valueForKey:#"address"]];
break;
case 2:
cell.textLabel.text = [NSString stringWithFormat:#"%# : %#",#"Age",[dictionary valueForKey:#"age"]];
break;
case 3:
cell.textLabel.text = [NSString stringWithFormat:#"%# : %#",#"Occupation",[dictionary valueForKey:#"occupation"]];
break;
case 4:
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.text = [NSString stringWithFormat:#"%# : %#",#"Rating",[rate valueForKey:#"average"]];
break;
case 5:
cell.textLabel.text = [NSString stringWithFormat:#"%# : %#",#"Total Rating",[rate valueForKey:#"totalRatings"]];
break;
}
Here's a way to completely overengineer the problem, but you may find some useful nuggets in there which will help you with your specific problem:
typedef enum MONTableViewCellID {
MONTableViewCellID_Name = 0,
MONTableViewCellID_Address,
MONTableViewCellID_Age,
MONTableViewCellID_Occupation,
MONTableViewCellID_Rating,
MONTableViewCellID_TotalRating
} MONTableViewCellID;
#interface MONTableViewStuff : NSObject
{
#private
NSDictionary * dictionary;
NSDictionary * rate;
UITableViewCell * cell;
NSIndexPath * indexPath;
}
#end
#implementation MONTableViewStuff
- (UITableViewCellAccessoryType)tableViewAccessoryTypeForRow:(NSUInteger)row
{
if (MONTableViewCellID_Rating == row) {
return UITableViewCellAccessoryDisclosureIndicator;
}
return UITableViewCellAccessoryNone;
}
- (NSString *)lhsTextForRow:(NSUInteger)row
{
switch (row) {
case MONTableViewCellID_Name :
return [dictionary objectForKey:#"firstname"];
case MONTableViewCellID_Address :
return #"Address";
case MONTableViewCellID_Age :
return #"Age";
case MONTableViewCellID_Occupation :
return #"Occupation";
case MONTableViewCellID_Rating :
return #"Rating";
case MONTableViewCellID_TotalRating :
return #"Total Rating";
default : {
assert(0 && "invalid row");
return #"";
}
}
}
- (NSString *)rhsTextForRow:(NSUInteger)row
{
switch (row) {
case MONTableViewCellID_Name :
return [dictionary objectForKey:#"lastname"];
case MONTableViewCellID_Address :
return [dictionary objectForKey:#"address"];
case MONTableViewCellID_Age :
return [dictionary objectForKey:#"age"];
case MONTableViewCellID_Occupation :
return [dictionary objectForKey:#"occupation"];
case MONTableViewCellID_Rating :
return [rate objectForKey:#"average"];
case MONTableViewCellID_TotalRating :
return [rate objectForKey:#"totalRatings"];
default : {
assert(0 && "invalid row");
return #"";
}
}
}
- (NSString *)separatorForRow:(NSUInteger)row
{
switch (row) {
case MONTableViewCellID_Name :
return #" ";
case MONTableViewCellID_Address :
case MONTableViewCellID_Age :
case MONTableViewCellID_Occupation :
case MONTableViewCellID_Rating :
case MONTableViewCellID_TotalRating :
return #" : ";
default : {
assert(0 && "invalid row");
return #"";
}
}
}
- (NSString *)textLabelTextForRow:(NSUInteger)row
{
return [NSString stringWithFormat:#"%#%#%#", [self lhsTextForRow:row], [self separatorForRow:row], [self rhsTextForRow:row]];
}
- (void)updateTextLabel
{
cell.textLabel.text = [self textLabelTextForRow:indexPath.row];
cell.accessoryType = [self tableViewAccessoryTypeForRow:indexPath.row];
}
#end
Another overengineered option that you may be able to steal some nuggets from is the object based approach:
MONTableViewStuff.h
typedef enum MONTableViewCellID {
MONTableViewCellID_Name = 0,
MONTableViewCellID_Address,
MONTableViewCellID_Age,
MONTableViewCellID_Occupation,
MONTableViewCellID_Rating,
MONTableViewCellID_TotalRating
} MONTableViewCellID;
#interface MONTableViewStuff : NSObject
#property (nonatomic, copy, readonly) NSDictionary * dictionary;
#property (nonatomic, copy, readonly) NSDictionary * rate;
#end
MONTableViewStuff.m
#implementation MONTableViewStuff
#synthesize dictionary;
#synthesize rate;
- (id)init
{
self = [super init];
if (0 != self) {
/* create an array of presenters ordered by MONTableViewCellID */
presenters =
[NSArray arrayWithObjects:
[[NamePresenter new] autorelease],
[[AddressPresenter new] autorelease],
[[AgePresenter new] autorelease],
[[OccupationPresenter new] autorelease],
[[RatingPresenter new] autorelease],
[[TotalRatingPresenter new] autorelease],
nil
];
}
return self;
}
- (void)updateTableViewCell
{
NSObject<MONUITableViewCellPresenter>* presenter = [presenters objectAtIndex:indexPath.row];
[presenter updateUITableViewCell:cell tableViewStuff:self];
}
#end
Where the presenters' interface looked like so:
#protocol MONUITableViewCellPresenter < NSObject >
#required
- (void)updateUITableViewCell:(UITableViewCell *)cell tableViewStuff:(MONTableViewStuff *)tableViewStuff;
#end
// our base presenter which handles the cells
#interface DefaultPresenter : NSObject
/** #return UITableViewCellAccessoryNone */
- (UITableViewCellAccessoryType)cellAccessoryTypeForTableViewStuff:(MONTableViewStuff *)tableViewStuff;
- (void)updateUITableViewCell:(UITableViewCell *)cell tableViewStuff:(MONTableViewStuff *)tableViewStuff;
#end
// required overrides
#protocol DefaultPresenterSubclass <MONUITableViewCellPresenter>
#required
- (NSString *)cellTextForTableViewStuff:(MONTableViewStuff *)tableViewStuff;
#end
// our specializations
#interface NamePresenter : DefaultPresenter <DefaultPresenterSubclass>
#end
#interface AddressPresenter : DefaultPresenter <DefaultPresenterSubclass>
#end
#interface AgePresenter : DefaultPresenter <DefaultPresenterSubclass>
#end
#interface OccupationPresenter : DefaultPresenter <DefaultPresenterSubclass>
#end
#interface RatingPresenter : DefaultPresenter <DefaultPresenterSubclass>
#end
#interface TotalRatingPresenter : DefaultPresenter <DefaultPresenterSubclass>
#end
And their implementations looked like so:
#implementation DefaultPresenter
- (UITableViewCellAccessoryType)cellAccessoryTypeForTableViewStuff:(MONTableViewStuff *)tableViewStuff
{
#pragma unused (tableViewStuff)
return UITableViewCellAccessoryNone;
}
- (NSString *)cellTextForTableViewStuff:(MONTableViewStuff *)tableViewStuff
{
#pragma unused (tableViewStuff)
assert(0 && "specialization required");
return 0;
}
- (void)updateUITableViewCell:(UITableViewCell *)cell tableViewStuff:(MONTableViewStuff *)tableViewStuff
{
cell.accessoryType = [self cellAccessoryTypeForTableViewStuff:tableViewStuff];
cell.textLabel.text = [self cellTextForTableViewStuff:tableViewStuff];
}
#end
#implementation NamePresenter
- (NSString *)cellTextForTableViewStuff:(MONTableViewStuff *)tableViewStuff
{
return [NSString stringWithFormat:#"%# %#",[tableViewStuff.dictionary valueForKey:#"firstname"], [tableViewStuff.dictionary valueForKey:#"lastname"]];
}
#end
#implementation AddressPresenter
- (NSString *)cellTextForTableViewStuff:(MONTableViewStuff *)tableViewStuff
{
return [NSString stringWithFormat:#"%# : %#",#"Address",[tableViewStuff.dictionary valueForKey:#"address"]];
}
#end
#implementation AgePresenter
- (NSString *)cellTextForTableViewStuff:(MONTableViewStuff *)tableViewStuff
{
return [NSString stringWithFormat:#"%# : %#",#"Age",[tableViewStuff.dictionary valueForKey:#"age"]];;
}
#end
#implementation OccupationPresenter
- (NSString *)cellTextForTableViewStuff:(MONTableViewStuff *)tableViewStuff
{
return [NSString stringWithFormat:#"%# : %#",#"Occupation",[tableViewStuff.dictionary valueForKey:#"occupation"]];
}
#end
#implementation RatingPresenter
+ (UITableViewCellAccessoryType)cellAccessoryType
{
return UITableViewCellAccessoryDisclosureIndicator;
}
- (NSString *)cellTextForTableViewStuff:(MONTableViewStuff *)tableViewStuff
{
return [NSString stringWithFormat:#"%# : %#",#"Rating",[tableViewStuff.rate valueForKey:#"average"]];
}
#end
#implementation TotalRatingPresenter
- (NSString *)cellTextForTableViewStuff:(MONTableViewStuff *)tableViewStuff
{
return [NSString stringWithFormat:#"%# : %#",#"Total Rating",[tableViewStuff.rate valueForKey:#"totalRatings"]];
}
#end
The thing you could do would be to make some kind of data objet containing the information you need to display in your stringWithFormat method.
And then make a NSDictionary that key value pair those object with the indexes...
But is all that work worth it in this particular case?
I doubt it.

How to implement initWithObjects?

How can I create a class with the initializer initWithObjects?
Or does it just make more sense to inherit from NSArray and work around it that way?
initWithObjects: is implemented using a C variable argument list. Here's an example implementation:
- (void)setContentByAppendingStrings:(NSString *)firstArg, ...
{
NSMutableString *newContentString = [NSMutableString string];
va_list args;
va_start(args, firstArg);
for (NSString *arg = firstArg; arg != nil; arg = va_arg(args, NSString*))
{
[newContentString appendString:arg];
}
va_end(args);
[contents autorelease];
contents = [newContentString retain];
}
See this page for more info.
#interface foo : NSObject {
NSArray* objects;
}
-(id)initWithObjects:(NSArray*)array;
#end
#implementation foo
-(id)initWithObjects:(NSArray*)array{
if(self = [super init]){
objects = array;
}
return self;
}
#end

Singleton Class iPhone

Ok, I'm trying to avoid global variables, so I read up on singleton classes.
This is a try to set and read a mutable array, but the result is null.
//Content.h
#interface Content : NSObject {
NSMutableArray *contentArray;
}
+ (Content *) sharedInstance;
- (NSMutableArray *) getArray;
- (void) addArray:(NSMutableArray *)mutableArray;
#end
.
//Content.m
#implementation Content
static Content *_sharedInstance;
+ (Content *) sharedInstance
{
if (!_sharedInstance)
{
_sharedInstance = [[Content alloc] init];
}
return _sharedInstance;
}
- (NSMutableArray *) getArray{
return contentArray;
}
- (void) addArray:(NSMutableArray *)mutableArray{
[contentArray addObject:mutableArray];
}
#end
And in a ViewController I added #import "Content.h", where I try to call this:
NSMutableArray *mArray = [NSMutableArray arrayWithObjects:#"test",#"foo",#"bar",nil];
Content *content = [Content sharedInstance];
[content addArray:mArray];
NSLog(#"contentArray: %#", [content getArray]);
You need to alloc and init the array first. Personally I'd do it in the init method of the content class like so:
-(id)init{
if(self = [super init]){
…the rest of your init code…
contentArray = [[NSMutableArray alloc] init];
}
return self;
}
You never actually alloc/initialise the contentArray array.

Instantiating Custom Class from NSDictionary

I have a feeling that this is stupid question, but I'll ask anyway...
I have a collection of NSDictionary objects whose key/value pairs correspond to a custom class I've created, call it MyClass. Is there an easy or "best practice" method for me to basically do something like MyClass * instance = [map NSDictionary properties to MyClass ];? I have a feeling I need to do something with NSCoding or NSKeyedUnarchiver, but rather than stumble through it on my own, I figure someone out there might be able to point me in the right direction.
The -setValuesForKeysWithDictionary: method, along with -dictionaryWithValuesForKeys:, is what you want to use.
Example:
// In your custom class
+ (id)customClassWithProperties:(NSDictionary *)properties {
return [[[self alloc] initWithProperties:properties] autorelease];
}
- (id)initWithProperties:(NSDictionary *)properties {
if (self = [self init]) {
[self setValuesForKeysWithDictionary:properties];
}
return self;
}
// ...and to easily derive the dictionary
NSDictionary *properties = [anObject dictionaryWithValuesForKeys:[anObject allKeys]];
There is no allKeys on NSObject. You'll need to create an extra category on NSObject like below:
NSObject+PropertyArray.h
#interface NSObject (PropertyArray)
- (NSArray *) allKeys;
#end
NSObject+PropertyArray.m
#import <objc/runtime.h>
#implementation NSObject (PropertyArray)
- (NSArray *) allKeys {
Class clazz = [self class];
u_int count;
objc_property_t* properties = class_copyPropertyList(clazz, &count);
NSMutableArray* propertyArray = [NSMutableArray arrayWithCapacity:count];
for (int i = 0; i < count ; i++) {
const char* propertyName = property_getName(properties[i]);
[propertyArray addObject:[NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]];
}
free(properties);
return [NSArray arrayWithArray:propertyArray];
}
#end
Example:
#import "NSObject+PropertyArray.h"
...
MyObject *obj = [[MyObject alloc] init];
obj.a = #"Hello A"; //setting some values to attributes
obj.b = #"Hello B";
//dictionaryWithValuesForKeys requires keys in NSArray. You can now
//construct such NSArray using `allKeys` from NSObject(PropertyArray) category
NSDictionary *objDict = [obj dictionaryWithValuesForKeys:[obj allKeys]];
//Resurrect MyObject from NSDictionary using setValuesForKeysWithDictionary
MyObject *objResur = [[MyObject alloc] init];
[objResur setValuesForKeysWithDictionary:objDict];
Assuming that your class conforms to the Key-Value Coding protocol, you could use the following: (defined as a category on NSDictionary for convenience):
// myNSDictionaryCategory.h:
#interface NSDictionary (myCategory)
- (void)mapPropertiesToObject:(id)instance
#end
// myNSDictionaryCategory.m:
- (void)mapPropertiesToObject:(id)instance
{
for (NSString * propertyKey in [self allKeys])
{
[instance setValue:[self objectForKey:propertyKey]
forKey:propertyKey];
}
}
And here's how you would use it:
#import "myNSDictionaryCategory.h"
//...
[someDictionary mapPropertiesToObject:someObject];
If your doing this sort of thing chances are your dealing with JSON and you should probably have a look at Mantle
https://github.com/Mantle/Mantle
You will then get a convenient method dictionaryValue
[anObject dictionaryValue];
Just add category for NSObject for getting dictionaryRepresentation from your custom objects (in my case using in JSON serialization only):
// NSObject+JSONSerialize.h
#import <Foundation/Foundation.h>
#interface NSObject(JSONSerialize)
- (NSDictionary *)dictionaryRepresentation;
#end
// NSObject+JSONSerialize.m
#import "NSObject+JSONSerialize.h"
#import <objc/runtime.h>
#implementation NSObject(JSONSerialize)
+ (instancetype)instanceWithDictionary:(NSDictionary *)aDictionary {
return [[self alloc] initWithDictionary:aDictionary];
}
- (instancetype)initWithDictionary:(NSDictionary *)aDictionary {
aDictionary = [aDictionary clean];
self.isReady = NO;
for (NSString* propName in [self allPropertyNames]) {
[self setValue:aDictionary[propName] forKey:propName];
}
//You can add there some custom properties with wrong names like "id"
//[self setValue:aDictionary[#"id"] forKeyPath:#"objectID"];
self.isReady = YES;
return self;
}
- (NSDictionary *)dictionaryRepresentation {
NSMutableDictionary *result = [NSMutableDictionary dictionary];
NSArray *propertyNames = [self allPropertyNames];
id object;
for (NSString *key in propertyNames) {
object = [self valueForKey:key];
if (object) {
[result setObject:object forKey:key];
}
}
return result;
}
- (NSArray *)allPropertyNames {
unsigned count;
objc_property_t *properties = class_copyPropertyList([self class], &count);
NSMutableArray *rv = [NSMutableArray array];
unsigned i;
for (i = 0; i < count; i++) {
objc_property_t property = properties[i];
NSString *name = [NSString stringWithUTF8String:property_getName(property)];
[rv addObject:name];
}
//You can add there some custom properties with wrong names like "id"
//[rv addObject:#"objectID"];
//Example use inside initWithDictionary:
//[self setValue:aDictionary[#"id"] forKeyPath:#"objectID"];
free(properties);
return rv;
}
#end
Also, you can see that my solution will not work with custom objects with nested objects or arrays. For Arrays - just change the lines of code in dictionaryRepresentation method:
if (object) {
if ([object isKindOfClass:[NSArray class]]) {
#autoreleasepool {
NSMutableArray *array = [NSMutableArray array];
for (id item in (NSArray *)object) {
[array addObject:[item dictionaryRepresentation]];
}
[result setObject:array forKey:key];
}
} else {
[result setObject:object forKey:key];
}
}