I have a class to perform little conversions like NSDate to NSString with a specific format, etc.
Every methods are class methods, eg +[Tools humanReadableStringForDate:(NSDate*)date];
I sometime need my method +[Tools A] to call a method +[Tools B] of my class, but inside a block.
Should I create a __block safeSelf = self; or is it unnecessary because I use class level methods ?
EDIT :
here is an example, not my actual code :
#implementation FileManager
+(void) uploadEveryFile:(void (^)(NSObject*))thingToDo :(NSArray*) fileArray {
for(NSString *s in fileArray) {
[[SomeWebAPI uploadFile:s withSuccess:^(NSNumber *responseCode) {
[self logUploadOk:s];
}];
}
}
+(void) logUploadOk:(NSString*)s {
NSLog(#"File upload ok : %#", s)
}
#end
I think this make things clearer. I like to use self keyword even for class methods when I can - in this example I can because I am in the same class and refer to a class level method - because it seems to make more sense, and can be helpful if I have to modify my class name.
So is it correct to write it like this ? Is it working but not really correct ? Do I really need to call logUploadOk using [FileManager logUploadOk:s] ?
Thank you !
It is unnecessary to use __block or __weak or anything like that. You are talking about self in a class method, which is the class object itself. The class object lives for the whole program, so memory management like retain and release on it have no effect. So you don't need to worry about retain cycles.
+ (NSString *)A
{
NSString *something = [Tools B];
NSString *something = [self B]; // both are same inside class method
}
+ (NSString *)B
{
//..
}
That's unnecessary because you're using class method, not instance method. To call Class methods, you use the class name: [Tools doThisForMe].
However, it sounds like you could use Objective-C Categories in this case. It would allow you to extend the different classes and make your code more readable such as [myNSDate humanReadableString].
In your case, it would go along the lines of:
NSDate+Human.h
#interface NSDate (Human)
- (NSString *)humanReadableString;
#end
NSDate+Human.m
#implementation NSDate (Human)
- (NSString *)humanReadableString {
// do whatever you want.
// now 'self' refers to the NSDate instance
}
#end
Related
I've got an NSManagedObject class that I want to override a setter to but I've been told it's good practice to not modify the automatically generated class file and create categories to instead extend them (because if you change the model and regenerate the file, you lose all your additions).
If I make a method for the setter in a category, it definitely runs the method (tested with NSLog), but I don't know how to assign the actual property value. Normally, I'd synthesise the property using
#synthesize finished = _finished;
so that I can access the property in the setter using _finished, like so:
- (void)setFinished:(NSNumber *)finishedValue {
_finished = finishedValue;
self.end_time = [NSDate date];
}
but where the property is defined in the NSManagedObject this doesn't seem possible.
You can do with subclassing see the doc here
- (void)setName:(NSString *)newName
{
[self willChangeValueForKey:#"name"];
[self setPrimitiveName:newName];
[self didChangeValueForKey:#"name"];
}
In a category, you can't add property value, only methods. So you will need to subClass in order to perform what you want.
There is an easy way to do so, try the following:
Model.h
#interface Model
#property(nonatomic,copy) NSString * string;
#end
Model + Override.m
#interface Model ()
{
NSString *_string;
}
#end
#implementation Model (Override)
- (void)setString:(NSString *)string
{
return _string = string;
}
#end
I'm quite a newbie in Objective C, though I have some background in Java reflection.
Here, I have a classic class method findAll that find all the domain objects from the database. The class Univers directly inherits from DomainObject
#interface DomainObject : NSObject
- (NSString *) execute : (NSString*) method withJson:(NSString*)json;
+ (NSString*)findAll: (NSString*)json;
#end
#implementation DomainObject
- (NSString *) execute: (NSString*) method withJson:(NSString*)json{
method = [NSString stringWithFormat:#"%#%#", method, #":"];
//method is 'findAll:'
NSString* result = [ self performSelector:
NSSelectorFromString(method) withObject:json];// Error here
return result;
}
#end
The code was working when findAll was NOT a class method (ie -findAll declaration), but now I have the error : NSInvalidArgumentException -[Univers findAll:]
It clearly seems that the runtime is looking for an instance method.
Any idea to find my class method ?
Instead of calling
NSString* result = [self performSelector:NSSelectorFromString(method) withObject:json];
you need to call
NSString* result = [[self class] performSelector:NSSelectorFromString(method) withObject:json];
for class methods.
After all it's the object instance's class that supposed to be calling the method, not the instance itself.
Short explanation: NSObject implements - (Class)class; (not to be mistaken with + (Class)class of similar effect, which NSObject implements, too!) which returns the Class object of your instance object. Keep in mind that in Objective-C in addition to plain instance objects, Classes are actual objects, too: objects of type Class, that is (vs. id, NSObject, …).
See the documentation for the -class method here.
Btw, you should probably wrap your method call into an conditional block to prevent exceptions caused by calls to missing methods.
SEL selector = NSSelectorFromString(method);
if ([[self class] respondsToSelector:selector]) {
NSString* result = [[self class] performSelector:selector withObject:json];
}
In general it's a common pattern in Objective-C to call an object's class method by receiving the class object via [object class].
Consider this case of a class called Foo implementing a convenience method for returning an autporeleased instance of itself (to be called via: Foo *newFoo = [Foo foo];):
While it would certainly be possible to implement said method like this (after all we know the object's class name, right?):
+ (id)foo {
return [[[Foo alloc] init] autorelease];
}
the correct way is this:
+ (id)foo {
return [[[self alloc] init] autorelease];
}
As the first one would cause problems with polymorphism in subclasses (Such as a subclass called FooBar, for which it should clearly be [FooBar alloc] …, not [Foo alloc] …. Luckily [[self class] alloc] solves this dynamically).
While this is clearly not the right place for a thorough explanation of this (rather offtopic one might say) it's certainly worth noting/warning about, imho.
As a part of my transition process from C++ to Objective-C, I intensively read book Cocoa and Objective C Up and Running.
In one of the book code examples, there is a line that does not make sense to me with my current level of knowledge:
It is a declaration of class method + (Photo*) photo;.
Could anybody explain me the reason, please, why the author had decided for the method (Photo*) photo; to declare it as a class method instead of instance method?
I have studiet the theory, that the instane method is something like a class member function and that class method is something like static function in C++. But this still does not answer my question.
Here is the declaration code:
#import <Foundation/Foundation.h>
#interface Photo : NSObject{
NSString* caption;
NSString* photographer;
}
+ (Photo*) photo;
- (NSString*) caption;
- (NSString*) photographer;
- (void) setCaption: (NSString*)input;
- (void) setPhotographer: (NSString*)input;
#end
The implementation code follows:
#import "Photo.h"
#implementation Photo
- (id)init
{
self = [super init];
if (self) {
[self setCaption:#"Default Caption"];
[self setPhotographer:#"Default Photographer"];
}
return self;
}
+ (Photo*) photo {
Photo* newPhoto = [[Photo alloc] init];
return [newPhoto autorelease];
}
- (NSString*) caption {
return caption;
}
- (NSString*) photographer {
return photographer;
}
- (void) setCaption:(NSString *)input {
[caption autorelease];
caption = [input retain];
}
- (void) setPhotographer: (NSString *)input {
[photographer autorelease];
photographer = [input retain];
}
- (void)dealloc
{
[self setCaption:nil];
[self setPhotographer:nil];
[super dealloc];
}
#end
The + (Photo*) photo method is a Factory Method that encapsulates the details of creating an object of the Photo class.
A Factory Method enforces
encapsulation, and allows an object to
be requested without inextricable
coupling to the act of creation.
In this particular example the information being hidden by the factory method is memory management, since the client does not need to worry about releasing the returned object.
It is a common practice in Objective-C APIs to provide factory methods in classes that return autoreleased objects of that same classes. These methods must not contain any of the words “alloc”, “new”, “copy”, or “mutableCopy”, which, according to the convention, indicates that the caller doesn't own the returned object, i.e. it doesn't have to be explicitly released.
Related resources:
Memory Management Rules
Meta answer:
One issue; that method should be
declared as returning id and should
return [[[self alloc] init]
autorelease]; (one line or two,
doesn't matter -- just should refer to
the Class directly). As it is, Photo
is gonna be a pain to subclass.
Expanding -- given this:
+ (Photo*) photo {
Photo* newPhoto = [[Photo alloc] init];
return [newPhoto autorelease];
}
If the class were subclassed, this factory method would not work without being overridden to do pretty much the same thing. However, since Objective-C doesn't support co-variance and contra-variance, there would be no way to declare the subclass's implementation of +photo to return an instance of the subclass without also running a significant risk of compiler warnings. Alternatively, you could down-cast the return value to the more specific class, but that is rife with fragility.
Instead, do this:
+ (id) photo {
id newPhoto = [[self alloc] init];
return [newPhoto autorelease];
}
This fixes both issues:
since it uses self, it'll instantiate an instance of whatever class it is implemented on, including subclasses of Photo.
since it returns id, callers can do both of the following without issue:
Photo *p = [Photo photo];
SubclassOfPhoto *s = [SubclassOfPhoto photo];
In this scenario, photo is a convenience method, which returns you an autoreleased instance of the class.
Since the purpose of photo is to give you an instance, it wouldn't make sense to make it an instance method which would require you to already have an instance.
If you're familiar with Factory Methods, the photo method is similar to that.
+photo is like a constructor. You need a way to get an object to send instance methods to, and this gives you an autoreleased one.
It is equivalent to a static method, as you say. In this case (and all cases of [ClassName className] methods) it's basically a factory method. You're asking the class to construct an instance of itself and pass it back. All such methods should return an autoreleased object.
You can safely ignore methods like that if you want - there will usually be an alloc+init equivalent, but it's often more convenient to use the class method, especially if you're creating a throaway object and don't want to retain it.
Finally, you'll sometimes find classes which require you to use the class method, as they'll hide some clever logic wherein an instance of another class is actually returned. You'll sometimes hear these described as 'class clusters'.
Could anybody explain me the reason, please, why the author had decided for the method (Photo*) photo; to declare it as a class method instead of instance method?
It's basically a wrapper of the constructor litany. Note the source:
+ (Photo*) photo {
Photo* newPhoto = [[Photo alloc] init];
return [newPhoto autorelease];
}
Allocate a new Photo, initialize it, mark it autorelease, and return it. Since it creates the object, there is no object yet to operate upon, ergo this needs to be a class method.
This question already has answers here:
What does #synchronized() do as a singleton method in objective C?
(6 answers)
Closed 3 years ago.
After reading the responses to a question about singletons in Objective C it appears that each solution makes some tradeoff in regards to threading in the instance accessor. i.e.
#synchronized(self)
{
if (sharedInstance == nil)
sharedInstance = [[MySingleton alloc] init];
}
return sharedInstance;
This essentially single-threads access to the singleton, and if it's something that's used frequently in an operation, seems like something that could cause threads to unnecessarily contend.
What's the downside to simply using the class object as the singleton instance, and exposing functionality via class methods, i.e.
#interface MySingleton : NSObject {
}
+ (void)doSomething;
#end
#implementation MySingleton
+ (void)initialize {
//do some setup if necessary
}
+ (void)doSomething {
//do something
}
#end
In this way we avoid doing the lock + check every time we want to reference the singleton object and we can also eliminate having to store it in a local or method ivar.
This approach also lets the runtime guarantee that only one instance (the Class object) exists in the system at any given time.
EDIT
There's more here than just threading, with a traditional singleton you usually write code like this:
MySingleton *instance = [MySingleton getSharedInstance];
NSObject *someResult = [instance getResult];
//or
if (instance.someProperty) {
//do something
}
However if your singleton is a class instance, you essentially eliminate the need call getSharedInstance all the time. Consider this code:
NSObject *someResult = [MySingleton getResult];
//or
if ([MySingleton someProperty]) {
//do something
}
I hear the point that you have to store your data in file local static variables, or in global variables (yuck). But it's really not all that different from a traditional singleton with the exception that you lose Objective-C 2.0 properties (instead you have to use traditional accessor methods).
Here's one key tradeoff for me that seems like a win. In a traditional singleton you end up overriding -copyWithZone, +allocWithZone, -retain, -retainCount, -release and -autorelease if you really want to get things right.
This seems like an awful lot of work to do every time you want to write a simple Singleton object (they happen to be pretty useful). So why not simply just replace it with this:
#implementation MySingleton
+ (void)initialize {
//do your setup
}
- (id)init {
NSAssert(NO, #"You should read the documentation on singletons.");
}
#end
It's a lot lighter in terms of code, and unless your consumers are really sneaky they won't ever create two instances.
Get to the point already
My question is really this:
Is there any drawback to using the Class object as the instance of your singleton?
It seems like you can take all the same steps in terms of threadsafety, memory efficiency etc. without having to remember to override so many methods and accessors or litter your code with instance checks.
With iOS 4.0 or later, by far the best solution is to just use dispatch_once, as in
+ (id)sharedInstance {
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
sharedInstance = [[MyClass alloc] init];
});
return sharedInstance;
}
You may also want to consider using a single dispatch_queue to serialize access to the internals of a class. If all your public methods just run a block on the same dispatch_queue then you won't have to worry about concurrency issues.
This is my first post on Stack Overflow... (so prepare for stupidity)
I think there is a hybrid solution that might be useful.
I want to set and get (global) values out of a singleton class without having calling "getSharedInstance". I'd want the code to look like this...
frameRate = Singleton.frameRate;
Singleton.frameRate = 42;
To achieve this, each variable we need to store in the singleton has a getter and setter class method. The class method then goes to an instance to store the data in an ivar. The instance isn't directly accessed by the main program.
The getter looks like this:
+ (int) frameRate
{
return [[Singleton instance] ivarFrameRate];
}
The (ugly) instance call is hidden inside the class code.
By calling the instance method here, the class method will automatically instantiate an object when first used. Once the singleton is instantiated, the instance stores ivars conventionally. Here, I am prefixing with "ivar" make the ivar explicit.
#property int ivarFrameRate;
and
#synthesize ivarFrameRate;
This automatically creates conventional getter (and setter) methods to access the ivar.
(edit - here is a complete example)
// Singleton.h
#import <Foundation/Foundation.h>
#interface Singleton : NSObject
{
float ivarFrameRate
}
#property float ivarFrameRate;
- (id) init;
+ (Singleton *) instance;
+ (float) frameRate;
+ (void) setFrameRate:(float)fr;
#end
and
// Singleton.m
#import "Singleton.h"
#implementation Singleton
#synthesize ivarFrameRate;
static Singleton* gInstance = NULL;
+ (Singleton*)instance
{
#synchronized(self)
{
if (gInstance == NULL)
gInstance = [[self alloc] init];
}
return(gInstance);
}
- (id)init
{
self = [super init];
return self;
}
+ (float) frameRate
{
return [[Singleton instance] ivarFrameRate];
}
+ (void) setFrameRate:(float)fr;
{
[[Singleton instance] setIvarFrameRate:fr];
}
This is fine, but still just changes your circumstances rather than fixes your problems. Unless you don't have any actual data tied to your singleton, in which case this will work just fine. Anytime you access central data you will need to properly make it thread-safe.
Additionally, without some kind of iVar I don't know of a way to store data (that is intended) directly in a class.
In the example above I would code it in this way, getting the same result as you are proposing and only taking the performance hit if we are creating/re-creating the singleton:
if (sharedInstance)
return sharedInstance;
#synchronized(self)
{
if (sharedInstance == nil)
sharedInstance = [[MySingleton alloc] init];
}
return sharedInstance;
Keep in mind that either way, if you are accessing data that is potentially changing on different threads then you'll have to make that code thread-safe anyway, either with very careful planning or using code to ensure there are no problems. I'd recommend a mix, but when in doubt the latter when at all possible. =)
If you use a class as your singleton, the only way to store data would be to use static file variables and global variables. If you are going to go so far that you make a class you don't plan to instantiate, you might as well just use standard C functions:
void doSomething(void);
void doSomething() {
//do something
}
I have a class Film, each of which stores a unique ID. In C#, Java etc I can define a static int currentID and each time i set the ID i can increase the currentID and the change occurs at the class level not object level. Can this be done in Objective-C? I've found it very hard to find an answer for this.
Issue Description:
You want your ClassA to have a ClassB class variable.
You are using Objective-C as programming language.
Objective-C does not support class variables as C++ does.
One Alternative:
Simulate a class variable behavior using Objective-C features
Declare/Define an static variable within the classA.m so it will be only accessible for the classA methods (and everything you put inside classA.m).
Overwrite the NSObject initialize class method to initialize just once the static variable with an instance of ClassB.
You will be wondering, why should I overwrite the NSObject initialize method. Apple documentation about this method has the answer: "The runtime sends initialize to each class in a program exactly one time just before the class, or any class that inherits from it, is sent its first message from within the program. (Thus the method may never be invoked if the class is not used.)".
Feel free to use the static variable within any ClassA class/instance method.
Code sample:
file: classA.m
static ClassB *classVariableName = nil;
#implementation ClassA
...
+(void) initialize
{
if (! classVariableName)
classVariableName = [[ClassB alloc] init];
}
+(void) classMethodName
{
[classVariableName doSomething];
}
-(void) instanceMethodName
{
[classVariableName doSomething];
}
...
#end
References:
Class variables explained comparing Objective-C and C++ approaches
As of Xcode 8, you can define class properties in Obj-C. This has been added to interoperate with Swift's static properties.
Objective-C now supports class properties, which interoperate with Swift type properties. They are declared as: #property (class) NSString *someStringProperty;. They are never synthesized. (23891898)
Here is an example
#interface YourClass : NSObject
#property (class, nonatomic, assign) NSInteger currentId;
#end
#implementation YourClass
static NSInteger _currentId = 0;
+ (NSInteger)currentId {
return _currentId;
}
+ (void)setCurrentId:(NSInteger)newValue {
_currentId = newValue;
}
#end
Then you can access it like this:
YourClass.currentId = 1;
val = YourClass.currentId;
Here is a very interesting explanatory post I used as a reference to edit this old answer.
2011 Answer: (don't use this, it's terrible)
If you really really don't want to declare a global variable, there another option, maybe not very orthodox :-), but works... You can declare a "get&set" method like this, with an static variable inside:
+ (NSString*)testHolder:(NSString*)_test {
static NSString *test;
if(_test != nil) {
if(test != nil)
[test release];
test = [_test retain];
}
// if(test == nil)
// test = #"Initialize the var here if you need to";
return test;
}
So, if you need to get the value, just call:
NSString *testVal = [MyClass testHolder:nil]
And then, when you want to set it:
[MyClass testHolder:testVal]
In the case you want to be able to set this pseudo-static-var to nil, you can declare testHolder as this:
+ (NSString*)testHolderSet:(BOOL)shouldSet newValue:(NSString*)_test {
static NSString *test;
if(shouldSet) {
if(test != nil)
[test release];
test = [_test retain];
}
return test;
}
And two handy methods:
+ (NSString*)test {
return [MyClass testHolderSet:NO newValue:nil];
}
+ (void)setTest:(NSString*)_test {
[MyClass testHolderSet:YES newValue:_test];
}
Hope it helps! Good luck.
On your .m file, you can declare a variable as static:
static ClassName *variableName = nil;
Then you can initialize it on your +(void)initialize method.
Please note that this is a plain C static variable and is not static in the sense Java or C# consider it, but will yield similar results.
In your .m file, declare a file global variable:
static int currentID = 1;
then in your init routine, refernce that:
- (id) init
{
self = [super init];
if (self != nil) {
_myID = currentID++; // not thread safe
}
return self;
}
or if it needs to change at some other time (eg in your openConnection method), then increment it there. Remember it is not thread safe as is, you'll need to do syncronization (or better yet, use an atomic add) if there may be any threading issues.
As pgb said, there are no "class variables," only "instance variables." The objective-c way of doing class variables is a static global variable inside the .m file of the class. The "static" ensures that the variable can not be used outside of that file (i.e. it can't be extern).
Here would be an option:
+(int)getId{
static int id;
//Do anything you need to update the ID here
return id;
}
Note that this method will be the only method to access id, so you will have to update it somehow in this code.
(Strictly speaking not an answer to the question, but in my experience likely to be useful when looking for class variables)
A class method can often play many of the roles a class variable would in other languages (e.g. changed configuration during tests):
#interface MyCls: NSObject
+ (NSString*)theNameThing;
- (void)doTheThing;
#end
#implementation
+ (NSString*)theNameThing { return #"Something general"; }
- (void)doTheThing {
[SomeResource changeSomething:[self.class theNameThing]];
}
#end
#interface MySpecialCase: MyCls
#end
#implementation
+ (NSString*)theNameThing { return #"Something specific"; }
#end
Now, an object of class MyCls calls Resource:changeSomething: with the string #"Something general" upon a call to doTheThing:, but an object derived from MySpecialCase with the string #"Something specific".
u can rename the class as classA.mm and add C++ features in it.
Another possibility would be to have a little NSNumber subclass singleton.