I have a class using a Block defined in the header like this:
#property (readwrite, copy) RequestSucceededBlock succeededBlock;
The property succeededBlock is already set with a Block. Is there a way to override this Block with another that still calls the original, similar to class inheritance?
I assume this is not possible, because class inheritance should be used to express things like that. Is it still possible?
Assuming you're talking about trying to have a replacement block in a subclass that still calls the superclass block, you can't inject a block into an existing block but you can fake it as follows:
// in MySubclass.h
#property (nonatomic, copy) RequestSucceededBlock subclassSucceededBlock;
// in MySubclass.m
- (RequestSucceededBlock)succeededBlock
{
[return subclassSucceededBlock];
}
- (void)setSucceededBlock:(RequestSucceededBlock)newSucceededBlock
{
// make sure this conforms to the definition of RequestSucceededBlock
RequestSucceededBlock combinedBlock = ^{
dispatch_async(dispatch_get_current_queue(), newSucceededBlock);
dispatch_async(dispatch_get_current_queue(), [super succeededBlock]);
};
subclassSucceededBlock = combinedBlock;
}
This is a bit odd though b/c it assumes the superclass has a default block assigned to succeededBlock that you want to dispatch. If your question has a different use in mind please clarify and I'll see if I can update this.
EDIT: added copy to iVar
Related
This question already has answers here:
Objective-C: Property / instance variable in category
(6 answers)
Closed 2 years ago.
I've got a form implementation in objective-c and I'd like to extend my widgets (NSButton, NSTextField, etc..) to contain additional string representing their unique identifier string to be used after submit event occur, which trigger generation of json contain all widget id/value pairs.
I've tried using categories to extend NSControl which is the common parent of all those widgets in the following way.
NSControl+formItemSupport.h
-------------------------------
#interface NSControl (formItemSupport)
#property NSString * formItemId;
#end
NSControl+formItemSupport.m
-------------------------------
#implementation NSControl (formItemSupport)
-(NSString *)formItemId {
return self.formItemId;
}
-(void)setFormItemId:(NSString *)formItemId {
self.formItemId = formItemId;
}
in the form.m file I import from NSControl+formItemSupport.m but when I try to set this field in NSButton : NSControl object. However, when I try to set the property formItemId, I get into infinite loop. Perhaps there's another way for extending objc class with variable based property without using inheritance ?
you can
#synthesize formItemId = _formItemId;
//synthesize needs local declaration of _formItemId;
#implementation ExtraWurst {
NSString *_formItemId;
}
but this is done behind the scene for you from Xcode without #synthesize.
Sometime it is still easier to define the use of an internal variable for a property in this way.
apart from that you can and have to change your setter and getter methods in the following way.
-(NSString *)formItemId {
return _formItemId;
}
-(void)setFormItemId:(NSString *)formItemId {
_formItemId = formItemId;
}
this will prevent you from ending up in a loop.
Why?
Because self.formItemId = refers to -(void)setFormItemId:
So you would call the setter inside the setter that will set with the same again and again aka an endless loop.
You can take care of the getter the same way as shown above.
Where to use self.yourProperty then?
You can use self.formItemId anywhere in the class but not inside getter and setter of formItemId.
Correctly mentioned, Instance variables may not be placed in categories.
Meaning if you need such you have to subclass UIControl but that breaks the inheritance of your used UIControls. You would have to subclass all your SpecialUIControls you are using later.
Another solution, you could define a constant in your implementation and go with objective-C runtime functions and associate this constant yourself. Beware because you transform the ObjectModel for all UIControl classes then..
#import "NSControl+formItemSupport.h"
#import <objc/runtime.h>
#implementation UIControl (formItemSupport)
NSString const *key = #"formItemSupport.forItemKey";
-(void)setFormItemId:(NSString *)formItemId {
objc_setAssociatedObject(self, &key, formItemId, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSString *)formItemId {
return objc_getAssociatedObject(self, &key);
}
#end
still, its much easier and safer and flexible to subclass your own UIControl instead to extent all subclasses inherited from UIControl.
Why is subclassing easier here?
As you mentioned you want to json later on with the given formItemId per Control you can make use of an archiver / unarchiver design pattern of your subclasses which are nice to jsonify later.
I think I've been using Objective-C properties incorrectly. Specifically, I've been treating them like instance variables.
Here's an example of a recent interface:
// AIClass.h
#import "AIDataUtils.h"
#interface AIViewController : UIViewController
#property (strong, nonatomic) AIDataUtils *dataUtils;
#end
Then, in my implementation, I would use self.dataUtils as a way for any method in the class to easily access the same thing. No object from the outside would ever be interacting with that property.
What I'm realizing is that what I should have been doing is importing and declaring AIDataUtils in the implementation and not the interface. I think that would look like this:
// AIClass.m
#import "AIDataUtils.h"
#interface AIViewController ()
{
AIDataUtils *dataUtils;
}
#end
#implementation AIViewController
- (void)viewDidLoad
{
[super viewDidLoad];
dataUtils = [[AIDataUtils alloc] init];
...
}
The docs say:
Avoid explicitly declaring public instance variables. Developers should concern themselves with an object’s interface, not with the details of how it stores its data.
My understanding here is if another object has no business touching AIDataUtils, don't put it in the interface. The fact that a property exists in an interface should be a hint that you're supposed to feed or do something with that property.
Am I hot or cold?
My understanding here is if another object has no business touching AIDataUtils, don't put it in the interface.
You're right, but that doesn't mean that you can't keep using properties for internal values too -- just don't declare them in your public interface. Usually, using a class extension as you've suggested is a fine way to have your properties while still keeping internal things (more or less) private.
There was a period in the evolution of Objective-C when properties were very helpful in managing memory -- if you used a property's accessors everywhere, you could worry a lot less about when to retain and when to release something because the accessors would do that for you. Now that we have ARC, the memory management aspect of properties is less important, but a lot of us are still conditioned to use properties even for internal stuff. If nothing else, internal-only properties can make your code a little more consistent-looking.
If you intend dataUtils to be a private implementation detail, then you shouldn't declare it in the #interface in the header file.
Even if you want to keep it private, you can still make it a property in the .m file:
#interface AIViewController ()
#property (strong, nonatomic) AIDataUtils *dataUtils;
#end
Whether to make it a property or just an instance variable is a matter of taste and depends on how you use it. For example, if you only want to allocate the AIDataUtils instance lazily, you might as well make it a property and do the lazy allocation in the getter.
If you decide to make it an instance variable, there's probably no reason to declare it in a class extension. You can just declare it in the #implementation:
#implementation AIViewController {
AIDataUtils *dataUtils;
}
- (void)viewDidLoad {
[super viewDidLoad];
dataUtils = [[AIDataUtils alloc] init];
...
You can learn more about where to declare instance variables in this answer.
I'm a beginner with Objective-C, and am trying to use a global variable. I know that this question has been asked a hundred times, but none of the answers have worked for me. I'm trying to declare a BOOL variable in one class, and check its value in another. This is what I'm working with:
SController.h:
#interface SController : UIViewController {
BOOL leftSide;
BOOL rightSide;
}
SController.m:
- (void)viewDidLoad {
leftSide = YES;
rightSide = YES;
}
Now, for the class I'm trying to access the value of the BOOLs in:
#import "SController.h"
#interface VViewController : UIViewController
{
}
And VViewController's .m:
- (void)viewDidLoad {
// See what the BOOL values from SController are.
}
What I've tried:
Going off of the previous related questions on here, I've tried putting "extern" in front of the BOOLs declaration in SController.h, but that did not work. I tried simply importing the SControllers header file into VViewController, and that did not work either. I'm very new to Objective-C and programming in general, so I'm having a tough time wrapping my head around basic concepts like this. I understand the potential issues surrounding using a global variable, but this program is very small and for personal use. If anyone can show me what to change to make this happen, that would be great.
Like the others said, don't use a global variable for that (and most other) purpose.
You created iVars and in order to access them, you need to expose them to other objects.
You generally do that by defining #properties in your SControllers header file. When doing that, you don't need to create iVars yourself, they are created implicitly. And methods to access the iVars are also automagically created (getters and setters).
Your SControllers header could look something like this:
#interface SController: UIViewController
//no need to declare the iVars here, they are created by the #property definitions
#property (nonatomic, assign) BOOL leftSide;
#property (nonatomic, assign) BOOL rightSide;
#end
In your other viewController you need a reference to the instance of SController you previously created and want to "talk" to (it is important you understand this), then you could access the instance variable through the generated getter/setter methods like so:
//this is "dot notation", the first line would be equivalent
//to writing: [sControllerInstance setLeftSide: YES]
sControllerInstance.leftSide = YES;
BOOL valueRightSide = sControllerInstance.rightSide;
Please read up on: objective-c properties, getters/setters and dot notation.
You will find plenty of information on google and SO
I know this is not the answer you're looking for, but try rethinking your app. Global variables is not the best way to go for Object oriented programming.
Create GlobalVariable.h header class file and defined following externs as follows
extern NSString * googleURL;
And then in your implementation GlobalVariable.m file
#import "GlobalVariable.h"
NSString * googleURL = #"www.google.co.uk";
And then import the class wherever you want to use it across.
By default the variables (as defined in your code) are protected. You can add the #public keyword before the 2 variables to make them public but it's not recommended. Generally you want to expose those as properties using the #property keyword
Example:
#interface SController : UIViewController {
#public
BOOL leftSide;
BOOL rightSide;
#protected
//other protected variables here
}
What is the semantic difference between these 3 ways of using ivars and properties in Objective-C?
1.
#class MyOtherObject;
#interface MyObject {
}
#property (nonatomic, retain) MyOtherObject *otherObj;
2.
#import "MyOtherObject.h"
#interface MyObject {
MyOtherObject *otherObj;
}
#property (nonatomic, retain) MyOtherObject *otherObj;
3.
#import "MyOtherObject.h"
#interface MyObject {
MyOtherObject *otherObj;
}
Number 1 differs from the other two by forward declaring the MyOtherObject class to minimize the amount of code seen by the compiler and linker and also potentially avoid circular references. If you do it this way remember to put the #import into the .m file.
By declaring an #property, (and matching #synthesize in the .m) file, you auto-generate accessor methods with the memory semantics handled how you specify. The rule of thumb for most objects is Retain, but NSStrings, for instance should use Copy. Whereas Singletons and Delegates should usually use Assign. Hand-writing accessors is tedious and error-prone so this saves a lot of typing and dumb bugs.
Also, declaring a synthesized property lets you call an accessor method using dot notation like this:
self.otherObj = someOtherNewObject; // set it
MyOtherObject *thingee = self.otherObj; // get it
Instead of the normal, message-passing way:
[self setOtherObject:someOtherNewObject]; // set it
MyOtherObject *thingee = [self otherObj]; // get it
Behind the scenes you're really calling a method that looks like this:
- (void) setOtherObj:(MyOtherObject *)anOtherObject {
if (otherObject == anOtherObject) {
return;
}
MyOtherObject *oldOtherObject = otherObject; // keep a reference to the old value for a second
otherObject = [anOtherObject retain]; // put the new value in
[oldOtherObject release]; // let go of the old object
} // set it
…or this
- (MyOtherObject *) otherObject {
return otherObject;
} // get it
Total pain in the butt, right. Now do that for every ivar in the class. If you don't do it exactly right, you get a memory leak. Best to just let the compiler do the work.
I see that Number 1 doesn't have an ivar. Assuming that's not a typo, it's fine because the #property / #synthesize directives will declare an ivar for you as well, behind the scenes. I believe this is new for Mac OS X - Snow Leopard and iOS4.
Number 3 does not have those accessors generated so you have to write them yourself. If you want your accessor methods to have side effects, you do your standard memory management dance, as shown above, then do whatever side work you need to, inside the accessor method. If you synthesize a property as well as write your own, then your version has priority.
Did I cover everything?
Back in the old days you had ivars, and if you wanted to let some other class set or read them then you had to define a getter (i.e., -(NSString *)foo) and a setter (i.e., -(void)setFoo:(NSString *)aFoo;).
What properties give you is the setter and getter for free (almost!) along with an ivar. So when you define a property now, you can set the atomicity (do you want to allow multiple setting actions from multiple threads, for instance), as well as assign/retain/copy semantics (that is, should the setter copy the new value or just save the current value - important if another class is trying to set your string property with a mutable string which might get changed later).
This is what #synthesize does. Many people leave the ivar name the same, but you can change it when you write your synthesize statement (i.e., #synthesize foo=_foo; means make an ivar named _foo for the property foo, so if you want to read or write this property and you do not use self.foo, you will have to use _foo = ... - it just helps you catch direct references to the ivar if you wanted to only go through the setter and getter).
As of Xcode 4.6, you do not need to use the #synthesize statement - the compiler will do it automatically and by default will prepend the ivar's name with _.
I want to fire some code when a property is accessed and changed. I use #property and #synthesize in my code for my ivars. The properties are retained, so I'd like to keep that memory management stuff automatically generated by #synthesize.
However, I assume that #synthesize tells the compiler to generate the accessor methods code right where #synthesize is, so most of the cases at the top of the code, right?
And when I have a property foo, I get -setFoo and -foo methods. Could I then just make a method like this, to execute some more custom code when a property is changed?
-(void)setFoo {
// custom stuff
}
Now that's a problem. How to execute the first one? I wouldn't love to have a different name here. Is there maybe a way to let the #synthesize directive create other names for getter and setter methods, which I then call easily? And I would still be able to use the dot syntax then to access them?
You can use #property and #synthesize just like you normally would, but provide a custom setter or getter (or both) and those will be used instead. Typically I will do something like this:
// Override the setter
- (void)setName:(NSString *)aName
{
if (name == aName)
return;
[name release];
name = [aName retain];
//custom code here
}
When I use the set property, it will invoke my custom method. However, the get will still be synthesized.
If you provide an implemnetation for the setters or getters it will use that instead of the generated implementation. Its not hard to implement the "retaining" aspect of the getters and setters that are generated for you by the compiler when u synthesize, so you can just write your own getters and setters i would say and go with that.
One wacky solution is to create an abstract super class that does gives you the normal property synthesis.
Then create a concrete subclass that you will actually use, and that simply implements and override method (same signature) and calls super to do the actual setting.
This allows you to do whatever you want to do before or after the call to super's implementation.
Example:
#interface ALTOClassA : NSObject
#property NSString *catName;
#end
Nothing else needed in the .m beyond the stubbed file for this test.
Create the subclass, nothing needed specially in the #interface
#import "ALTOClassA.h"
#interface ALTOClassAJunior : ALTOClassA
#end
In the #implementation we do our override.
#import "ALTOClassAJunior.h"
#implementation ALTOClassAJunior
- (void)setCatName:(NSString*)aCatName {
NSLog(#"%#",NSStringFromSelector(_cmd));
[super setCatName:aCatName];
NSLog(#"after super: self.catName %#", self.catName);
}
#end
In use:
ALTOClassAJunior *aCAJ = [ALTOClassAJunior new];
NSLog(#"aCAS.catName %#", aCAJ.catName);
NSLog(#"set it to George.");
[aCAJ setCatName:#"George"];
NSLog(#"aCAS.catName %#", aCAJ.catName);
This allows you to leverage the autogenerated code, and still do stuff you want to do with your class. Abstract Super Class is often a useful solution for many things.
Yes, in your #property declaration, you can specify the getter and setter methods.
#property (readwrite,getter=privateGetFoo,setter=privateSetFoo:) NSObject * foo;
In your foo and setFoo: methods, call [self privateGetFoo] or [self privateSetFoo:f] then your custom code.
The object can also set an observer on itself with addObserver:forKeyPath:options:context:.
That said, I don't think either of these are very clean ways to do things. Better to write your own getter/setter as others have suggested.