Cradle to Grave Devotion: Objective C Notes
@property
In Objective C, @property
is used to declare properties in a class. It is a way to define instance variables (ivars) and their associated getter and setter methods. You can use @property
to declare properties in the interface section of a class.
Here is an example of how to declare a property:
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger age;
@end
You can also specify attributes for the property.
Here are some common attributes for memory management. Note that you can only use one of these attributes at a time:
-
strong
(default): This means that the property retains a strong reference to the object. -
weak
: This means that the property does not retain the object and allows it to be deallocated if there are no strong references to it. -
assign
: This means that the property does not retain the object and simply assigns it. This one is usually used for primitive types likeNSInteger
,CGFloat
, etc. -
copy
: This means that the property creates a copy of the object when it is assigned. -
retain
: This is similar tostrong
, but it is used in manual reference counting (MRC) instead of automatic reference counting (ARC). Deprecated in ARC.
Here are some common attributes for thread safety and access control. Note that you can only use one of these attributes at a time:
-
atomic
(default): This means that the property is thread-safe and uses atomic access. -
nonatomic
: This means that the property is not thread-safe and does not use atomic access.
Here are some common attributes for access control. Note that you can only use one of these attributes at a time:
-
readwrite
(default): This means that the property can be both read and written to. -
readonly
: This means that the property can only be read and not written to.
Other attributes you can use with @property
include:
-
getter=
: This allows you to specify a custom getter method name. -
setter=
: This allows you to specify a custom setter method name.
These below are some attributes that just used for documentation and do not affect the behavior of the property unless you implement the methods yourself:
-
nullable
: This indicates that the property can benil
. -
nonnull
: This indicates that the property cannot benil
. -
null_resettable
: This indicates that the property can benil
and will be reset to a default value when it is set tonil
.
For @property
, you can access the property using dot notation and when you access the property with dot notation, the compiler will automatically call the getter or setter method for you.
Categories of Objective C
There is a very interesting syntax in Objective C: the category.
A category is a way to add methods to an existing class without modifying the original class.
To use a category, you first need to define it in a header file (.h
file) and then implement it in an implementation file (.m
file or .mm
file).
Here is an example of a category that extends the NSString
class to add a method that reverses a string:
// NSString+Reverse.h
#import <Foundation/Foundation.h>
@interface NSString (Reverse)
- (NSString *)reversedString;
@end
// NSString+Reverse.m
#import "NSString+Reverse.h"
@implementation NSString (Reverse)
- (NSString *)reversedString {
NSMutableString *reversed = [NSMutableString stringWithCapacity:[self length]];
for (NSInteger i = [self length] - 1; i >= 0; i--) {
[reversed appendFormat:@"%C", [self characterAtIndex:i]];
}
return reversed;
}
We usually name the files with the format ClassName+CategoryName.h
and ClassName+CategoryName.m
. With these files, now you can use the reversedString
method on any NSString
object:
// import the category header file
#import "NSString+Reverse.h"
NSString *original = @"Hello, World!";
NSString *reversed = [original reversedString];
Of course, you can also add class methods (+
methods) to a category. But note that you cannot add new properties to a category, and you cannot access the ivars (instance variables) of the original class directly.
You can define multiple categories for the same class, but be careful to avoid method name conflicts.
You can also use the methods defined in a category in another category, and you just need to import the category header file in the implementation file of the other category.
Class Extensions
Class extensions are also called anonymous categories.
Unlike normal categories, class extensions are defined and implemented in implementation files, and usually used to add private methods or properties to a class.
Here is an example of a class extension:
// Person.mm
#import "Person.h"
#import <Foundation/Foundation.h>
@interface Person ()
@property (nonatomic, strong) NSString *privateProperty;
- (void)privateMethod;
@end
@implementation Person
- (void)privateMethod {
NSLog(@"This is a private method.");
}
@end
The privateProperty
and privateMethod
are only accessible within the Person
class.
Actually, you can still access the private methods from outside the class using performSelector
. For example:
Person *person = [[Person alloc] init];
[person performSelector:@selector(privateMethod)];
// With parameters, but only support at most two parameters
[person performSelector:@selector(privateMethod:withArg:) withObject:@"arg1" withObject:@"arg2"];
Protocols
Protocols in Objective C are similar to interfaces in other languages. They define a set of methods that a class can implement.
You can use @protocol
to define a protocol, and then use @optional
or @required
to specify whether the methods are optional or required. The default is @required
. And when you use @optional
or @required
, all the methods following it will be optional or required until the end of the protocol or the next @optional
or @required
.
Here is an example of a protocol:
@protocol MyProtocol
@required
- (void)requiredMethod;
- (void)anotherRequiredMethod;
@optional
- (void)optionalMethod;
- (void)anotherOptionalMethod;
@end
To declare a class that conforms to a protocol, you can use the <ProtocolName>
syntax in the class declaration. If the class implements more than one protocol, you can separate them with commas.
@interface MyClass : NSObject <MyProtocol, AnotherProtocol>
@end
When a class conforms to a protocol, it must implement all the required methods of the protocol. If it does not implement all the required methods, the compiler will generate a warning or error.
And you can specify that a property conforms to protocols, like this:
@interface MyClass
// We use 'id' for properties that conform to protocols
@property (nonatomic, strong) id<MyProtocol> myProperty;
@end
For optional methods, you may want to check if the object responds to the method before calling it, using respondsToSelector:
:
if ([myObject respondsToSelector:@selector(optionalMethod)]) {
[myObject optionalMethod];
}
It is possible to declare a protocol conforming to another protocol, like this:
@protocol MyProtocol <AnotherProtocol>
// We just declare that 'MyProtocol' conforms to 'AnotherProtocol'
// and we don't need to implement any methods here.
@end
When you declare a class that conforms to a protocol, you must implement all the required methods of the protocol. For example:
// In the .h file
@interface MyClass <MyProtocol>
@end
// In the .m file
@implementation MyClass
- (void)requiredMethod {
// Implementation of the required method
}
@end
Enjoy Reading This Article?
Here are some more articles you might like to read next: