iOS Name of This Way of Building and Returning an Object in Objective-C

iOS Name of this way of building and returning an object in Objective-C

That is a "Statement Expression", which is a GCC feature (understood by Clang as well),
see http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html:

A compound statement enclosed in parentheses may appear as an
expression in GNU C. This allows you to use loops, switches, and local
variables within an expression.

The value of the expression is the value of the last subexpression in the compound statement.

How to Return a Custom Objective-C Object from a Class Method?

Apple's Objective-C docs recommend you use objectWithParams: grammar for class methods (constructors). So in your case, you should change your existing method name to

+ (Crop *)cropWithName:(NSString *)name

And call it with Crop *turnip = [Crop cropWithName:@"Turnip];

and then in your for loop you can check if the passed in name equals the name of your object with [name isEqualToString:turnip.name].

This will work, however it seems as though every time that method is called you're creating a ton of Crop objects - time intensive on your part, and memory intensive on the device. Instead, you should look into making a plist file that uses a dictionary to represent each kind of Crop, and then in your creation method you can use your passed in name to look up all the other information about the specified crop. Then you can just return one instance of Crop instead of instantiating a massive amount.

Here's a link to Apple documentation that explains plists:

https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/PropertyLists/Introduction/Introduction.html

Specifically, in any objects that I want to pull from a plist I define the following method that takes values from a dictionary and sets an object's properties:

- (id)initWithDictionary:(NSDictionary *)dictionary
{
self = [super init];

[self setValuesForKeysWithDictionary:dictionary];

return self;
}

And then in a class where I want to access an array of data, I would create a synthesized @property and then define this method (in this case, I've got Song objects):

- (NSMutableArray *)songs
{
if (_songs == nil)
{
NSArray *songDicts = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"ChillMix" ofType:@"plist"]];

_songs = [[NSMutableArray alloc] initWithCapacity:[songDicts count]];

// Fast enumeration //
for (NSDictionary *currDict in songDicts)
{
Song *song = [[Song alloc] initWithDictionary:currDict];
[_songs addObject:song];
}
}
return _songs;
}

Here is a sample project I've developed: https://github.com/Jlawr3nc3/MusicLibraryiOS

[NSArray arrayWithContentsOfFile:] should be your new best friend. It's awesome. If you can format your XML in plist format, you're down to one. single. line. to parse data. (PS normal XML is annoying as hell to parse on iOS so this is a huge time save if you can avoid straight up XML).

Also, I'm not sure what the use case would be for creating a crop object based on a view's title. Since you're already aware of the name of the crop before the view is instantiated, you could create a Crop object and set a Crop property of the view to the crop object you created, and then in viewDidLoad just do self.title = self.crop.name;. Finally, if you've got a UITableView of crop objects you shouldn't populate the table view with static text; instead populate it with objects you create from a plist, and then in didSelectRowAtIndexPath: you can do [self.arrayOfCrops objectAtIndex:indexPath.row] to get the object you tapped on, and pass it in with the view you load. Anyway, check out Apple's sample code for more info on plists and tableviews etc, 'cause they've got a lot of information on this exact stuff.

Transform (or copy) an object to a subclass instance in Objective-C

It is not possible to transform an object into an instance of a subclass in Objective-C. However, with the class below you can supply an instance of both the object and the subclass and have the values of all properties copied to the subclass instance. This implementation works with both Objective-C object types and C primitives. You do not have to specify (or indeed even determine) the properties that need to be copied, providing you know that the important variables are visible and can be set (i.e., there are no properties that are exposed as "read only" or not exposed at all, whose values cannot be recalculated by the class). This method is thus relatively robust for known classes and will not require updating to support future changes you make in your object class that fit these parameters. It is iOS 8 compatible.

This class provides four class methods:

+ (id) copyObject:(id)object toSubclassObject:(id)subclassObject

Copies all properties of object to subclassObject. If the subclassObject is not a subclass of object, nil is returned.

+ (NSDictionary *) propertiesOfObject:(id)object;

Returns a dictionary of all visible properties of an object, including those from all its superclasses (other than NSObject).

+ (NSDictionary *) propertiesOfClass:(Class)class;

Returns a dictionary of all visible properties of a class, including those from all its superclasses (other than NSObject).

+ (NSDictionary *) propertiesOfSubclass:(Class)class;

Returns a dictionary of all visible properties that are specific to a subclass. Properties for its superclasses are not included.

Header:

//  SYNUtilities.h

#import <Foundation/Foundation.h>

@interface SYNUtilities : NSObject
+ (id) copyObject:(id)object toSubclassObject:(id)subclassObject;
+ (NSDictionary *) propertiesOfObject:(id)object;
+ (NSDictionary *) propertiesOfClass:(Class)class;
+ (NSDictionary *) propertiesOfSubclass:(Class)class;
@end

Implementation:

#import "SYNUtilities.h"
#import <objc/runtime.h>
#import <objc/message.h>

@implementation SYNUtilities
+ (id) copyObject:(id)object toSubclassObject:(id)subclassObject
{
if (![[subclassObject class] isSubclassOfClass:[object class]]) {
return nil;
}

NSDictionary * properties = [self propertiesOfObject:object];
NSLog(@"Properties of %@:\n%@", [object class], properties);

for (NSString * property in properties) {
SEL selector = NSSelectorFromString(property);
if (selector) {
id value = [object valueForKey:property];
[subclassObject setValue:value forKey:property];
}
}
return subclassObject;
}

+ (NSDictionary *) propertiesOfObject:(id)object
{
Class class = [object class];
return [self propertiesOfClass:class];
}

+ (NSDictionary *) propertiesOfClass:(Class)class
{
if (class == NULL) {
return nil;
}

NSMutableDictionary * properties = [NSMutableDictionary dictionary];
[self propertiesForHierarchyOfClass:class onDictionary:properties];
return [NSDictionary dictionaryWithDictionary:properties];
}

+ (NSDictionary *) propertiesOfSubclass:(Class)class
{
if (class == NULL) {
return nil;
}

NSMutableDictionary *properties = [NSMutableDictionary dictionary];
return [self propertiesForSubclass:class onDictionary:properties];
}

+ (NSMutableDictionary *)propertiesForHierarchyOfClass:(Class)class onDictionary:(NSMutableDictionary *)properties
{
if (class == NULL) {
return nil;
}

if (class == [NSObject class]) {
// On reaching the NSObject base class, return all properties collected.
return properties;
}

// Collect properties from the current class.
[self propertiesForSubclass:class onDictionary:properties];

// Collect properties from the superclass.
return [self propertiesForHierarchyOfClass:[class superclass] onDictionary:properties];
}

+ (NSMutableDictionary *) propertiesForSubclass:(Class)class onDictionary:(NSMutableDictionary *)properties
{
unsigned int outCount, i;
objc_property_t *objcProperties = class_copyPropertyList(class, &outCount);
for (i = 0; i < outCount; i++) {
objc_property_t property = objcProperties[i];
const char *propName = property_getName(property);
if(propName) {
const char *propType = getPropertyType(property);
NSString *propertyName = [NSString stringWithUTF8String:propName];
NSString *propertyType = [NSString stringWithUTF8String:propType];
[properties setObject:propertyType forKey:propertyName];
}
}
free(objcProperties);

return properties;
}

static const char *getPropertyType(objc_property_t property) {
const char *attributes = property_getAttributes(property);
char buffer[1 + strlen(attributes)];
strcpy(buffer, attributes);
char *state = buffer, *attribute;
while ((attribute = strsep(&state, ",")) != NULL) {
if (attribute[0] == 'T' && attribute[1] != '@') {
// A C primitive type:
/*
For example, int "i", long "l", unsigned "I", struct.
Apple docs list plenty of examples of values returned. For a list
of what will be returned for these primitives, search online for
"Objective-c" "Property Attribute Description Examples"
*/
NSString *name = [[NSString alloc] initWithBytes:attribute + 1 length:strlen(attribute) - 1 encoding:NSASCIIStringEncoding];
return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];
}
else if (attribute[0] == 'T' && attribute[1] == '@' && strlen(attribute) == 2) {
// An Objective C id type:
return "id";
}
else if (attribute[0] == 'T' && attribute[1] == '@') {
// Another Objective C id type:
NSString *name = [[NSString alloc] initWithBytes:attribute + 3 length:strlen(attribute) - 4 encoding:NSASCIIStringEncoding];
return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];
}
}
return "";
}

@end

Swift equivalent of Objective-C expression?

Unlike Swift, Objective-C - because it is C - can create a local scope anywhere with simple curly braces. Moreover, by a GCC extension to the C language, this scope can be used to generate a value — namely, the last expression in the curly braces — when the curly braces are themselves surrounded by parentheses. Thus, this is a way of defining, configuring, and returning keyFrame inline.

So, to understand in Swift terms what it means, consider it as roughly equivalent to this sort of thing, which is actually a fairly common Swift idiom (I call it define-and-call):

let arr : [UIView] = [
{
let v = UIView(frame:CGRectMake(0,0,100,100))
v.opaque = true
v.backgroundColor = UIColor.redColor()
return v
}()
]

detect the class of a property with name in objective-c

i have the name of this property as NSString

You can use the function class_getProperty(Class cls, const char *name) to find the property for a given class. Then use property_getAttributes(objc_property_t property) to get the property's attributes, including the encoded type string. Read the Declared Properties section of the Objective-C Runtime Programming Guide for more info.

iOS: Object returning *nil description* after alloc and init

When using %@ to print NSObject, it calls debugDescription that by default calling the description method of that object and your Part object always have nil description.

You better solve this by changing the description property name to something else, because it conflicts with the description method of NSObject.

See also: NSObject description and debugDescription

@property retain, assign, copy, nonatomic in Objective-C

The article linked to by MrMage is no longer working. So, here is what I've learned in my (very) short time coding in Objective-C:

nonatomic vs. atomic
- "atomic" is the default. Always use "nonatomic". I don't know why, but the book I read said there is "rarely a reason" to use "atomic". (BTW: The book I read is the BNR "iOS Programming" book.)

readwrite vs. readonly
- "readwrite" is the default. When you @synthesize, both a getter and a setter will be created for you. If you use "readonly", no setter will be created. Use it for a value you don't want to ever change after the instantiation of the object.

retain vs. copy vs. assign

  • "assign" is the default. In the setter that is created by @synthesize, the value will simply be assigned to the attribute. My understanding is that "assign" should be used for non-pointer attributes.
  • "retain" is needed when the attribute is a pointer to an object. The setter generated by @synthesize will retain (aka add a retain count) the object. You will need to release the object when you are finished with it.
  • "copy" is needed when the object is mutable. Use this if you need the value of the object as it is at this moment, and you don't want that value to reflect any changes made by other owners of the object. You will need to release the object when you are finished with it because you are retaining the copy.

Objective-C add functionality to every method of an object

Lemme break this into two parts since I just can't get the connection between your two questions.

I. Create a new method with the "old" implementation and change to name to a schema like "___name"

That's fairly easy, although I don't understand how that would be able to solve your problem. You still can't pass down variadic function arguments to such a method (and you're right, that can't be done in C).

IMP swapImpForSelector(Class cls, SEL sel, IMP newImp)
{
Method m = class_getInstanceMethod(cls, sel);
IMP oldImp = method_setImplementation(m, newImp);

NSString *newSel = [NSString stringWithFormat:@"__prefixed_%@", NSStringFromSelector(sel)];
const char *type = method_getTypeEncoding(m);
class_addMethod(cls, NSSelectorFromString(newSel), oldImp, type);

return oldImp;
}

II. If you want to pass variadic arguments between functions, you may need to fall back to heavy assembly hackage. Fortunately, some smart people have already done that for you.

Either use the NSInvocation class, or if it isn't sufficient, then libffi is even lower-level.

How to write computed initializers in Objective C?

I use some thing like this

@interface TestClass : NSObject
@property (nonatomic, readonly) UIButton* button;
@end

@implementation TestClass
@synthesize button=_button;
-(UIButton*)button
{
if (_button==nil) {
_button = [UIButton buttonWithType:UIButtonTypeSystem];
...
}
return _button;
}

@end


Related Topics



Leave a reply



Submit