I'm trying to figure out why my NSTextFields are only retained in the first method sendVarsToButton but not in the updateTotal method. I need to access the values from the TextField set in the first method but I can't because it seems like my IBOutlets deallocate themselves after the sendVarsToButton method. Can you help me please!?
Here's my .h
#import <Cocoa/Cocoa.h>
#import "TransactionViewController.h"
#class TransactionButtonModel;
#interface TransactionButtonController : TransactionViewController
{
NSMutableArray *buttonsArrays;
TransactionViewController *transactionViewController;
TransactionButtonModel *transactionButtonModel;
}
#property(nonatomic,retain) IBOutlet NSTextField *nom;
#property(nonatomic,retain) IBOutlet NSTextField *descriptionText;
#property(nonatomic,retain) IBOutlet NSTextField *prix;
#property(nonatomic,retain) IBOutlet NSTextField *CPUField;
#property(nonatomic,retain) IBOutlet NSTextField *quantite;
#property(nonatomic,retain) IBOutlet NSTextField *total;
-(void)sendVarsToButton:(NSString *)name:(NSString *)description:(double)price:(double)CPU:(long)tag;
-(void)updateTotal:(int)newQuantity;
-(void)addQuantiteToExistingProduct:(long)tag;
-(IBAction)removeProductFromView:(id)sender;
Here's my .m
#import "TransactionButtonController.h"
#import "TransactionViewController.h"
#import "TransactionButtonModel.h"
#implementation TransactionButtonController
#synthesize prix;
#synthesize nom;
#synthesize descriptionText;
#synthesize CPUField;
#synthesize total;
#synthesize quantite;
//In this method, everything works fine
-(void)sendVarsToButton:(NSString *)name :(NSString *)description :(double)price :(double)CPU:(long)tag
{
[nom setTag:tag];
[descriptionText setTag:tag];
[prix setTag:tag];
[CPUField setTag:tag];
[quantite setTag:tag];
[total setTag:tag];
nom.stringValue = name;
descriptionText.stringValue = description;
[prix setDoubleValue : price];
CPUField.doubleValue = CPU;
total.doubleValue = [TransactionButtonModel calculateButtonTotal:quantite.intValue :prix.doubleValue];
NSLog(#"retain! :%lu",[[prix viewWithTag:tag] retainCount]); // returns 2
[transactionButtonModel release];
}
-(void)updateTotal:(int)newQuantity
{
NSLog(#"retain! :%lu",[[prix viewWithTag:2] retainCount]); //returns 0
[total setDoubleValue:[TransactionButtonModel calculateButtonTotal:newQuantity :prix.doubleValue]]; // value of prix = 0 and prix = null
NSLog(#"Updated! :%i",newQuantity);
}
-(void)dealloc
{
[nom release];
[quantite release];
[prix release];
[total release];
[descriptionText release];
}
Thanks in advance.
It sounds like you have a few problems here. In no particular order:
You're releasing transactionButtonModel in sendVarsToButton::::: even though you didn't create it there and there's no particularly obvious reason you'd want to. This seems like probably a memory management error, but it's hard to say without context.
You're looking to the reference counting mechanisms to see why a variable is null. Overreleasing an object does not set variables referencing that object to null — it would just be a junk pointer and probably crash your program. The most likely reasons for a variable to be unexpectedly null are a) methods running in a different order than you expect, or b) having two different instances of your class that you're treating as though they're the same one. My money would be on B in this case. You're probably creating two instances of this class, one of which is actually showing the view and the other being essentially "blank." Try logging self in the two methods and see if it's the same object.
In one method you're logging viewWithTag:tag and in the other you're logging viewWithTag:2 — it's not necessarily a safe assumption that tag is 2.
prix is an NSTextField — why are you asking it for subviews? NSTextField isn't generally expected to have any useful subviews. There seems to be something odd in this design.
Your method names are nuts with all those bare colons. It's hard to read and often leads to mistakes down the line (due to the likelihood of misreading the code when you're not "in the moment" and the fact that it violates the language's idioms).
You're depending on retainCount to track memory management. The value returned by retainCount is questionable at best and often downright deceptive because things get retained and autoreleased all the time, and retainCount won't give you enough information to account for that. If you have a memory management problem (which doesn't appear to be this case with your variable becoming nil), a good approach would be to use Instruments and the debugger to track it down, not random retainCount logging.
Related
There is a need to run some code when one object get dealloc. E.g, I set up one observer which updates the label A's text when object B's name changed. When label A's retain count reach 0, I want to remove the observer from B.
Possible solutions:
1 Subclass and call the clean code in dealloc.
2 Create a wrapper class which able to run arbitrary code in dealloc and associate this object to label A. When A get dealloc, the associated object get dealloc too (suppose only A holds the strong ref to it), then the code get called.
I don't like the 1st one since it is so intrusive that makes it barely useless, need to subclass just for some easy stuff. So I am using No.2.
Do you have any comments? How do you do it?
I put my solution here in case someone needed.
#interface ExecuteWrapper : NSObject
#property (nonatomic, copy) void(^block)();
-(void)dealloc;
#end
#implementation ExecuteWrapper
-(void)dealloc{
if(self.block){
self.block();
}
}
#end
#implementation NSObject (SLUtil)
+(void)executeWhenDealloc:(NSObject *)object block:(void(^)())block{
static char key;
NSMutableArray *executeWrapperArray = [object associatedValueForKey:&key];
if ( executeWrapperArray == nil){
executeWrapperArray = [NSMutableArray array];
[object associateValue:executeWrapperArray withKey:&key];
}
ExecuteWrapper *executeWrapper = [[ExecuteWrapper alloc] init];
executeWrapper.block = block;
[executeWrapperArray addObject:executeWrapper];
}
#end
In client code
[NSObject executeWhenDealloc:labelA block:^{
// clean up code
}];
Note: Keep in mind that don't hold a strong ref to label A in the label
I have spent a few days learning Objective-C and have a few questions about #property. I have experience with C# so understand the need for pointers, initialization etc.
So as an example:
#interface MyClass : NSObject
{
IBOutlet UIImageView *image;
}
#property (retain, nonatomic) UIImageView *image
#end
#implementation MyClass
#synthesise image
#end
I understand that #synthesise is used to create the #property. But I have a few questions just to help me clear things up:
Does the #property duplicate or replace my original definition, or does it merely set up the mutibility and atomicity of the original?
Does #synthesise remove my need to use image = [[UIImageView alloc] init]?
If I do not provide a #property and still go ahead creating and destroying my variable manually, does that make any difference?
Ultimately, is the difference between the 2, #property gives you more flexibility with regards to memory management and multi-threading and the normal one gives you the defaults.
Does the #prototype duplicate or replace my original definition, or does it merely set up the mutibility and atomicity of the original?
The ivar declaration of image is redundant when using the most recent compiler releases.
The former declares an ivar (type + name + instance storage).
The property declaration specifies the type, name, storage (in more recent compiler releases), declares the accessor methods (e.g. - (UIImageView *)image; and - (void)setImage:(UIImageView *)pImage;), and other property specifiers (which are used when the accessors are generated by the compiler).
Does #synthesise remove my need to use image = [UIImageView alloc]?
No. You still need to implement your initializer and dealloc (in MRC) appropriately.
If I do not provide an #property and still go ahead creating and destroying my variable manually, does that make any difference?
That would be fine, when you do not want/need boilerplate accessor methods generated for you. It's a design choice. Not every ivar needs accessor methods.
Ultimately, is the difference between the 2, #property gives you more flexibility with regards to memory management and multi-threading and the normal one gives you the defaults.
The biggest reason they exist is convenience. Properties save a lot of boilerplate code.
There is no more flexibility with properties -- properties implement the most practical uses.
It's infrequent that atomicity (in this context) is equivalent to proper thread safety and correct concurrent execution.
1) The property does not replace the class member. A property is a declaration that you want the accessors (getter and setter) for a class member to perform certain "automatic" tasks and have a certain name.
For example:
#interface MyClass : NSObject
{
NSInteger __myInt;
}
#property (assign) NSInteger myInt;
#end
#implementation MyClass
#synthesize myInt=__myInt;
#end
The above code, for all intents and purposes, is causing the following methods to be automatically generated at compile time:
-(NSInteger) myInt
{
return self->__myInt;
}
-(void) setmyInt:(NSInteger)val_
{
self->__myInt = val_;
}
Of course, what happens "in the background" when Xcode compiles your program is a bit different and more nuanced, but this is basically what happens.
2) I'm not entirely clear what you mean by this one... You always need to alloc and init your variables, regardless of accessor synthesis.
3) No. Properties/synthesis are only needed for a) convenience, be it syntactic or atomicity for multithreading, and b) external access to members inside your class.
EDIT:
To clarify on multithreading and properties, declaring a property nonatomic does a great deal for thread safety. This, and my response to #3, addresses your last concern in your question.
You can do this:
#interface MyClass : NSObject
#property (retain, nonatomic) IBOutlet UIImageView *image;
#end
#implementation MyClass
#synthesize image;
#end
Does the #prototype duplicate or replace my original definition, or does it merely set up the mutibility and atomicity of the original?
The property adds things on-top of the ivar like KVO and thread safety if it's atomic.
Does #synthesise remove my need to use image = [UIImageView alloc]?
No
If I do not provide an #property and still go ahead creating and destroying my variable manually, does that make any difference?
If you don't make a property you lose out on the things a property gets you like KVO, it's a judgment and api call on how the variable will be used. Under arc it is much easier to use straight up ivars because you don't have to replicate the retaining and releasing the property did automatically.
The 'image' in #property (retain, nonatomic) UIImageView *image line is just a name of the property and IBOutlet UIImageView *image; is an ivar which you access through self.image. I always name an ivar for property the same as the name but add _ :
UIImage * image_;
#property (retain, nonatomic) UIImageView *image;
#synthesize image = image_;
If you will not create an ivar for your property the Xcode do it automatically for you (the name of the ivar will be the same as the name of property)
I'm not sure I understood how alloc and retain work.
Recently I discovered that the NSString properties were not retained and I had to add [myString copy] when I set them. Which makes me wonder if I misunderstood the whole way of using retain/alloc
Please, may someone tell me if I'm doing it correctly? I read a lot and had a look on open source projects, this let me thing that I may have been wrong since the beginning.
Here is my way of doing it:
/**** VIEW.h *****/
#import "MyClass.h"
#interface MyViewController : UIViewController {
//Is the following line really necessary?
MyClass *myObject;
}
#property (nonatomic, retain) MyClass *myObject;
- (void)defineObject;
#end
.
/**** VIEW.m *****/
#import "VIEW.h"
#implementation MyViewController
#dynamic myObject;
- (void)viewDidLoad
{
[super viewDidLoad];
[self defineObject];
NSLog(#"My object's name is: %#", myObject.name);
}
- (void)defineObject
{
//Here particularly, Why doesn't it work without both alloc and init
//shouldn't "#property (nonatomic, retain) MyClass *myObject;" have done that already?
myObject = [[MyClass alloc] initPersonalised];
[myObject setName:#"my name"];
}
.
/**** MyClass.h *****/
#interface MyClass : NSObject {
//not sure if this line is still necessary
NSString *name;
}
#property (nonatomic, retain) NSString *name;
- (id)initPersonalised;
- (void)setName:(NSString *)name;
- (NSString *)name;
#end
.
/**** MyClass.m *****/
#import "MyClass.h"
#implementation MyClass
#dynamic name;
(id)initPersonalised{
self = [super init];
name = #"Undefined";
}
- (void)setName:(NSString *)name{
self.name = [name copy];
}
- (NSString *)name{
return [self.name copy];
}
#end
I hope you can bring a bit of light, after months of programming this way, I'm less and less sure of doing it well.
This is indeed a topic that every Objective C programmer stumbles upon. There are a few things one needs to know:
Instance variable vs. property access
Within MyViewController,
myObject = xxx;
and
self.myObject = xxx;
are two different things. The first directly assigns to the instance variable and does neither release to old referenced insance nor retain the newly assigned instance. The latter one uses the property setter and thus releases the old and retains the new value.
Deallocation
Even when you have declared an implemented a property that takes care of retaining and releases the values, it won't take care of deallocation when your object (MyViewController in your case) is released. So you must explicitly release it in dealloc:
-(void) dealloc {
[myObject release];
[super dealloc];
}
Now to your code:
The snippet:
myObject = [[MyClass alloc] initPersonalised];
is perfectly okay. When you create an object, you use the pair of alloc and initXXX. The always create an instance with the reference count set to 1. So by directly assigning it to the instance variable, you create a clean constellation. I don't see no other way of creating the instance.
In MyClass you could use #synthesize name instead of #dynamic. Then the compiler would implement name and setName: automatically and you wouldn't need to do it yourself.
Finally, your missing dealloc.
Update:
If you use:
self.myObject = [[MyClass alloc] initPersonalised];
then you have a memory leak because initPesonalised sets the reference count to 1 and the setter of myObject increases it to two. If you want to use the setter, then I has to be:
MyClass* mo = [[MyClass alloc] initPersonalised];
self.myObject = [[MyClass alloc] initPersonalised];
[mo release];
It would be different if you weren't using initXXX to create a new instance. The class NSString for example has many methods called stringXXX, which create a new instance (or return a shared one) that has (conceptually) a reference count of 1 that will later automatically decreased by one. Then you better use the setter:
self.name = [NSString stringWithFormat: #"instance %d", cnt];
If you want to use copy instead of retain for your string property (which is good practice), then you can simply declare your property like this:
#property (nonatomic, copy) NSString *name;
When you then use #synthesize to implement the getter and setter, the compiler will generate them using copy instead of retain.
And NSString *name; is necessary even if you use #property and/or #synthesize to implement the property.
Alloc and init are methods that always go hand-in-hand. alloc allocates space for your object, and init initializes your object to some value. When you call alloc, you are responsible for freeing that object later. If you call copy, you are also responsible for releasing that object later. It's considered good practice to always initialize your objects right after you allocate them.
Now, to answer the questions I found in your code.
#interface MyViewController : UIViewController {
//Is the following line really necessary?
MyClass *myObject;
}
So is that line necessary? That depends. Does it make sense that your object has a MyClass as a property? This is a question only you can answer based on your design. I recommend you to study Object-Oriented Programming in more depth.
- (void)defineObject
{
//Here particularly, Why doesn't it work without both alloc and init
//shouldn't "#property (nonatomic, retain) MyClass *myObject;" have done that already?
myObject = [[MyClass alloc] initPersonalised];
[myObject setName:#"my name"];
}
Not necessarily. You are just providing a pointer to an object of the specified kind. The moment you set your property, depending on the property modifiers, your class will know what to do with MyObject.
In that way, there's no need to call [yourObject copy]. In this way your properties will be copied instead of being retained. Just don't forget to release it later in your -dealloc method, like you would with retain properties.
All in all, this is what I recommend you to study a bit more:
Object-Oriented Programming (not related to your issue, but I can tell you are not comfortable using it. Objective-C is heavily object oriented, so you want to understand OOP).
iOS Memory Management.
You can have a look at the Memory Management Guide. It will help you to better understand the alloc & retain concepts; hope this helps you.
I developing iPad games. I encounter this thing. This is my sample code:
Method 1:
Foo.h
#interface Foo : UIView{
UILabel *title;
.... // Other objects like UISlider, UIbuttons, etc.
}
// I add #property for all the objects.
#property (nonatomic, retain) UILabel *title;
... blablabla
Foo.m
// I synthesize all the properties.
#synthesize title;
... blablabla
// Release in dealloc method
[title release];
....
[super dealloc];
Method 2:
Foo.h
#interface Foo : UIView{
UILabel *title;
.... // Others object like UISlider, UIbuttons, etc.
}
// But this time I didn't add #property, synthesize and release.
Foo.m
// When I need the label, I allocate it:
title = [[UILabel alloc] initWithRect: CGRect(10, 10, 100, 30)];
title.text = #"test";
[self addSubview: title];
[title release];
Both method 1 and 2 work, but what's the difference between the 2 methods (method2 has less code)?
Which method should I use and why?
Has it something to do with memory management?
Method 2 is technically incorrect since by sending -release to title you indicate that you are no longer interested in it. You should make it nil straight after, or better yet, make it a local variable.
Method 1 is absolutely fine and has the advantage that, outside of -dealloc provided you always use the property to refer to it, you do not need to worry about getting -retain and -release -right.
The difference is that, in Method 2, you won't have access to the title from outside the Foo object. Instance variable are private to the class.
Also, with you need to make sure you balance the alloc/retain and releases.
I have a situation where it seems like I need to add instance variables to a category, but I know from Apple's docs that I can't do that. So I'm wondering what the best alternative or workaround is.
What I want to do is add a category that adds functionality to UIViewControllers. I would find it useful in all my different UIViewControllers, no matter what specific UIViewController subclass they extend, so I think a category is the best solution. To implement this functionality, I need several different methods, and I need to track data in between them, so that's what led me to wanting to create instance methods.
In case it's helpful, here's what I specifically want to do. I want to make it easier to track when the software keyboard hides and shows, so that I can resize content in my view. I've found that the only way to do it reliably is to put code in four different UIViewController methods, and track extra data in instance variables. So those methods and instance variables are what I'd like to put into a category, so I don't have to copy-paste them each time I need to handle the software keyboard. (If there's a simpler solution for this exact problem, that's fine too--but I would still like to know the answer to category instance variables for future reference!)
Yes you can do this, but since you're asking, I have to ask: Are you absolutely sure that you need to? (If you say "yes", then go back, figure out what you want to do, and see if there's a different way to do it)
However, if you really want to inject storage into a class you don't control, use an associative reference.
Recently, I needed to do this (add state to a Category). #Dave DeLong has the correct perspective on this. In researching the best approach, I found a great blog post by Tom Harrington. I like #JeremyP's idea of using #property declarations on the Category, but not his particular implementation (not a fan of the global singleton or holding global references). Associative References are the way to go.
Here's code to add (what appear to be) ivars to your Category. I've blogged about this in detail here.
In File.h, the caller only sees the clean, high-level abstraction:
#interface UIViewController (MyCategory)
#property (retain,nonatomic) NSUInteger someObject;
#end
In File.m, we can implement the #property (NOTE: These cannot be #synthesize'd):
#implementation UIViewController (MyCategory)
- (NSUInteger)someObject
{
return [MyCategoryIVars fetch:self].someObject;
}
- (void)setSomeObject:(NSUInteger)obj
{
[MyCategoryIVars fetch:self].someObject = obj;
}
We also need to declare and define the class MyCategoryIVars. For ease of understanding, I've explained this out of proper compilation order. The #interface needs to be placed before the Category #implementation.
#interface MyCategoryIVars : NSObject
#property (retain,nonatomic) NSUInteger someObject;
+ (MyCategoryIVars*)fetch:(id)targetInstance;
#end
#implementation MyCategoryIVars
#synthesize someObject;
+ (MyCategoryIVars*)fetch:(id)targetInstance
{
static void *compactFetchIVarKey = &compactFetchIVarKey;
MyCategoryIVars *ivars = objc_getAssociatedObject(targetInstance, &compactFetchIVarKey);
if (ivars == nil) {
ivars = [[MyCategoryIVars alloc] init];
objc_setAssociatedObject(targetInstance, &compactFetchIVarKey, ivars, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[ivars release];
}
return ivars;
}
- (id)init
{
self = [super init];
return self;
}
- (void)dealloc
{
self.someObject = nil;
[super dealloc];
}
#end
The above code declares and implements the class which holds our ivars (someObject). As we cannot really extend UIViewController, this will have to do.
I believe it is now possible to add synthesized properties to a category and the instance variables are automagically created, but I've never tried it so I'm not sure if it will work.
A more hacky solution:
Create a singleton NSDictionary which will have the UIViewController as the key (or rather its address wrapped as an NSValue) and the value of your property as its value.
Create getter and setter for the property that actually goes to the dictionary to get/set the property.
#interface UIViewController(MyProperty)
#property (nonatomic, retain) id myProperty;
#property (nonatomic, readonly, retain) NSMutableDcitionary* propertyDictionary;
#end
#implementation UIViewController(MyProperty)
-(NSMutableDictionary*) propertyDictionary
{
static NSMutableDictionary* theDictionary = nil;
if (theDictionary == nil)
{
theDictioanry = [[NSMutableDictionary alloc] init];
}
return theDictionary;
}
-(id) myProperty
{
NSValue* key = [NSValue valueWithPointer: self];
return [[self propertyDictionary] objectForKey: key];
}
-(void) setMyProperty: (id) newValue
{
NSValue* key = [NSValue valueWithPointer: self];
[[self propertyDictionary] setObject: newValue forKey: key];
}
#end
Two potential problems with the above approach:
there's no way to remove keys of view controllers that have been deallocated. As long as you are only tracking a handful, that shouldn't be a problem. Or you could add a method to delete a key from the dictionary once you know you are done with it.
I'm not 100% certain that the isEqual: method of NSValue compares content (i.e. the wrapped pointer) to determine equality or if it just compares self to see if the comparison object is the exact same NSValue. If the latter, you'll have to use NSNumber instead of NSValue for the keys (NSNumber numberWithUnsignedLong: will do the trick on both 32 bit and 64 bit platforms).
This is best achieved using the built-in ObjC feature Associated Objects (aka Associated References), in the example below just change to your category and replace associatedObject with your variable name.
NSObject+AssociatedObject.h
#interface NSObject (AssociatedObject)
#property (nonatomic, strong) id associatedObject;
#end
NSObject+AssociatedObject.m
#import <objc/runtime.h>
#implementation NSObject (AssociatedObject)
#dynamic associatedObject;
- (void)setAssociatedObject:(id)object {
objc_setAssociatedObject(self, #selector(associatedObject), object, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)associatedObject {
return objc_getAssociatedObject(self, #selector(associatedObject));
}
See here for the full tutorial:
http://nshipster.com/associated-objects/
It mentioned in many document's online that you can't create create new variable in category but I found a very simple way to achieve that. Here is the way that let declare new variable in category.
In Your .h file
#interface UIButton (Default)
#property(nonatomic) UIColor *borderColor;
#end
In your .m file
#import <objc/runtime.h>
static char borderColorKey;
#implementation UIButton (Default)
- (UIColor *)borderColor
{
return objc_getAssociatedObject(self, &borderColorKey);
}
- (void)setBorderColor:(UIColor *)borderColor
{
objc_setAssociatedObject(self, &borderColorKey,
borderColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
self.layer.borderColor=borderColor.CGColor;
}
#end
That's it now you have the new variable.
Why not simply create a subclass of UIViewController, add the functionality to that, then use that class (or a subclass thereof) instead?
Depending on what you're doing, you may want to use Static Category Methods.
So, I assume you've got this kind of problem:
ScrollView has a couple of textedits in them. User types on text edit, you want to scroll the scroll view so the text edit is visible above the keyboard.
+ (void) staticScrollView: (ScrollView*)sv scrollsTo:(id)someView
{
// scroll view to someviews's position or some such.
}
returning from this wouldn't necessarily require the view to move back, and so it doesn't need to store anything.
But that's all I can thinkof without code examples, sorry.
I believe it is possible to add variables to a class using the Obj-C runtime.
I found this discussion also.