How to suppress objective C analyser warning with categories - ios

I'm using the static code analyser in objective C and I found that using categories to spread a big file in multiple files causes the following problem:
#interface TestClass : UIViewController
#property (nonatomic, assign) UITableView* myTableView;
#end
#implementation TestClass
#end
#interface TestClass (someCategory)
#end
#implementation TestClass (someCategory)
- (void) someMethod
{
// ...
CGRect tableViewRect =
CGRectMake( sectionRect.origin.x,
sectionRect.origin.y + sectionRect.size.height + 1.0,
sectionRect.size.width,
tableViewHeight);
myTableView = [[UITableView alloc] initWithFrame:(CGRect) tableViewRect
style:(UITableViewStyle) UITableViewStylePlain];
[self.view addSubView: (UIView*) myTableView];
[myTableView release];
}
#end
Problem # 1: Compiling TestClass(someCategory) gives me an error "use of undeclared identifier 'theArray'".
-> Adding the prefix "self.myTableView" seems to fix the problem.
Problem # 2: Once I have added the "self." prefix before "myTableView", the code analyser complains "incorrect decrement of the reference count of an object that is not owned at this point by the caller"
->I have seen this before in my code: easy to fix by removing the "self." prefix in other, non categorized classes.
So I have a catch 22 situation!
- I can't have a class category without prefixing the properties that I use with "self."
- The code analyser gives me warnings because it does not seem to understand that my category owns an object that it allocates and frees.
Fixing either of these two problems would work for me
(a) finding a way to avoid specifying the ".self" prefix when referencing an attribute from my category implementation
(b) finding a way to make the code analyser happy with the fact that I own "self.xxx" where "xxx" is a property of the class that I am categorizing.

If you need to hold a reference to your table view for the life of the object, you should release it in the dealloc method. Saying [object release] is effectively saying you don't need a reference to the object any more.
If you don't need a reference to the table view, there's no need to use an instance variable/property. Just set up a temporary UITableView * pointer in your method.
Releasing an object from a property getter is usually a bad idea (see this question: Incorrect decrement of the reference count of an object that is not owned at this point by the caller)

Related

Why are class objects the property attribute of retain and not copy? [duplicate]

This question already has answers here:
Objective-C declared #property attributes (nonatomic, copy, strong, weak)
(4 answers)
Closed 6 years ago.
I was trying to pass a custom object to the next view controller and I encountered this error -[ClassName copyWithZone:] unrecognized selector sent to instance
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"attemptDetails"])
{
ResultsVC *vc = segue.destinationViewController;
vc.selectedEntry = selectedEntry;
}
}
#property (nonatomic, retain) ClassName *selectedEntry; //Why is it retain and not copy?
I'm still very confused with property attributes and why certain types use certain attributes, like NSString uses (nonatomic, copy) and CLLocationCoordinate2D uses (nonatomic, readonly).
Could someone explain or link a reference to me how each property attribute works? Much thanks!
There are lots of descriptions for property attributes explanation,
Reference links,
Objective-C ARC: strong vs retain and weak vs assign
https://stackoverflow.com/a/4511004/4294543
#property and retain, assign, copy, nonatomic in Objective-C
Short & simple my understanding is like,
retain : It's working on the created object, and it just increase the reference count.
Here in your case you have already model class object so not need to copy in the second vc property,you just need to retain it to second vc property.
copy : The value you assigned to property can be copied & used for other purposes too(create shallow copy of object & need when object is mutable & need to release after finish with it).
nonatomic : Thread access is faster but you can't simultaneously access & change your property.
readonly : You can't directly assign the property new value.
Even i have run your case in the my project,
#import "ViewController.h"
#import "TestViewController.h"
#import "CustomClass.h"
#interface ViewController (){
CustomClass *classT;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
classT = [[CustomClass alloc]init];
classT.test = YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)btn:(id)sender {
TestViewController * vc = [self.storyboard instantiateViewControllerWithIdentifier:#"TestViewController"];
vc.className = classT;
[self presentViewController:vc animated:YES completion:nil];
}
#end
#import <UIKit/UIKit.h>
#import "CustomClass.h"
#interface TestViewController : UIViewController
#property (nonatomic,retain) CustomClass *className; // Work as i said
//#property (nonatomic,copy) CustomClass *className; // Makes a copy of an object, and returns it with retain count of 1. If you copy an object, you own the copy. This applies to any method that contains the word copy where “copy” refers to the object being returned thats why here you will get crash
#end
I have read couple of good article for memory management. According to rypress
Retain Attribute : The retain attribute is the Manual Retain Release version of strong, and it has the exact same effect: claiming ownership of assigned values. You shouldn’t use this in an Automatic Reference Counted environment.
Copy Attribute : The copy attribute is an alternative to strong. Instead of taking ownership of the existing object, it creates a copy of whatever you assign to the property, then takes ownership of that. Only objects that conform to the NSCopying protocol can use this attribute.
Even I went through some good link of stackoverflow as well. Joshua Nozzi's answer gave good explanation for retain vs copy.
Retain vs. Copy - Declared properties use retain by default (so you can simply omit it altogether) and will manage the object's reference count automatically whether another object is assigned to the property or it's set to nil; Use copy to automatically send the newly-assigned object a -copy message (which will create a copy of the passed object and assign that copy to the property instead - useful (even required) in some situations where the assigned object might be modified after being set as a property of some other object (which would mean that modification/mutation would apply to the property as well).
Also found good example here.
Code :
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:#"First",#"Second", nil];
NSMutableArray *copiedArray = [array mutableCopy];
NSMutableArray *retainedArray = [array retain];
[retainedArray addObject:#"Retained Third"];
[copiedArray addObject:#"Copied Third"];
NSLog(#"array = %#",array);
NSLog(#"Retained Array = %#",retainedArray);
NSLog(#"Copied Array = %#",copiedArray);
Output :
array = (
First,
Second,
"Retained Third"
)
2013-12-19 17:15:49.380 RetainVsCopy[2876:c07] Retained Array = (
First,
Second,
"Retained Third"
)
2013-12-19 17:15:49.381 RetainVsCopy[2876:c07] Copied Array = (
First,
Second,
"Copied Third"
)
See, both array and Retained Array are having same contents. This is because both are pointing to same memory/instance/object. Where as contents of Copied Array are different. This is because copy created a separate instance.
In Objective C you will find that each class actually has a structure behind it. The properties are shortcuts which create the value in structure, a getter and a setter. For instance:
#interface MyClass
#property id myValue;
#end
Will create:
#interface MyClass {
id _myValue;
}
#property id myValue;
#end
#implementation
- (id)myValue {
return _myValue;
}
- (void)setMyValue:(id)myValue {
_myValue = myValue;
}
#end
Now these flags such as retain and copy add additional logic to the setters and getters. Using copy will actually create a setter as:
- (void)setMyValue:(id)myValue {
_myValue = [myValue copy];
}
Which means that the value must have the copy method implemented. Since your object does not it crashes.
Why to use copy is for safety. This is rarely important for something as strings but it is important for something like an array. So for instance you create a property #property NSArray *myArray; which expects an un-mutable array but the problem is that you can set a mutable array as well: myClassInstance.myArray = [[NSMutableArray alloc] init];. Now 2 modules have the access to the same mutable array. So if the first object starts modifying the array while the other one expects the array to always be the same you may find some issues. For instance MyClass instance may use it as a data source for the table view and at some point the array is mutated but the cells are not added/removed and the table view will cause a crash.
To be honest you can simply leave all of these as default and modify them only when you really need to. The case like above is highly unlikely anyway.

iOS Class Method

#interface TestObj :NSObject
#property(copy, nonatomic)NSString *name;
#end
#implementation TestObj
- (void)testName{
NSLog(#"name:%#",self.name);
}
#end
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
id tclass =[TestObj class];
void * vid = &tclass;
[(__bridge id)vid testName];
}
#end
log :
name: <ViewController: 0x7ff3584b6580>
My understanding is vid is a pointer to the address of the TestObj class object, then why vid can be sent directly to the testName instance method?
Also, why the testName method calls the NSLog will output <ViewController: 0x7ff3584b6580>instead of nil?
Thank.
I think you are basically getting lucky that you aren't crashing with that code.
First, class methods start with a + not a - -- so that is an instance method you are implementing.
#interface TestObj :NSObject
#property(copy, nonatomic)NSString *name;
#end
#implementation TestObj
+ (void)testName{
NSLog(#"name:%#", #"TestObj"); // cannot reference ivars or properties in class method
}
#end
...
Class classObject = [TestObj class];
[classObject testName];
You don't want to take pointers to class objects (or instances either). The Objective-C runtime will dereference the pointer you give it, in order to find the "isa" instance variable, which will be the Class it belongs to. The "isa" of a class object is the "meta-class", which contains the list of class methods, so that is how class method lookup works. In your example, it would dereference the pointer and find the TestObj class, meaning it is thinking it is calling a method on a TestObj instance when it's not -- you have not allocated one, but it's really just a garbage pointer. But, it will still (by complete luck) get into your instance method implementation, but "self" isn't really a valid instance. However, it looks like whatever the value is, just so happens to respond to a -name method and return either an NSString with that value or the UIViewController instance itself. Or maybe it's trying to deference the instance variable based on the garbage pointer and ending up with a pointer to the ViewController instance by happenstance. I think that would try to call a -name method though.
Anyways, tl;dr -- your code is quite wrong (don't use & pointers of classes or instances) and you are just getting lucky you aren't crashing. The (bridge id) cast is hiding the warning which was trying to help you.

Declared property is a subclass, but my view controller thinks its its superclass

Background info
I have a view controller that is running a cocos2d scene (so I can put UIkit objects on top of the scene).
My app is crashing with the following error:
2014-10-25 11:20:04.426 AppName[24166:992733] -[CCScene avatar]: unrecognized selector sent to instance 0x7c5a3270
2014-10-25 11:20:04.428 AppName[24166:992733] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[CCScene avatar]: unrecognized selector sent to instance 0x7c5a3270'
I know that the reason the app is crashing is because its trying to call the getter method avatar on a CCScene, instead of the CHCreateAvatarScene which is a subclass of CCScene. If I look in the debugger, the VC thinks that my currentScene property is of type CCScene, not CHCreateAvatarScene so obviously it can't find the Avatar property. Am I declaring it wrong? I can't figure out why this is the case. I'm also a bit of a programming newbie, just FYI. Its probably an obvious mistake.
CHCreateAvatarViewController.h
#import "CHCreateAvatarViewController.h"
#import "CHCreateAvatar.h"
#import "CHAvatarAttribute.h"
#import "CHAvatarAttributeOption.h"
#import "CHAttributeData.h"
#import "CHCreateAvatarScene.h"
#import "CHAttachment.h"
#interface CHCreateAvatarViewController () <CocosViewControllerDelegate, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
...
#property (strong, nonatomic) CHCreateAvatarScene *currentScene;
...
#end
#implementation CHCreateAvatarViewController
...
#pragma mark - CocosViewControllerDelegate
-(CCScene *)cocosViewControllerSceneToRun:(CocosViewController *)cocosViewController
{
//This will load the Spritebuilder file which is a loaded as a CCScene.
// I then told it to expect a CHCreateAvatarScene because otherwise I was getting an 'invalid pointer' error.
// I also tried changing the return type of this method to CHCreateAvatarScene to see if that would have any effect but it didn't, so I changed it back.
self.currentScene = (CHCreateAvatarScene *)[CCBReader loadAsScene:#"CreateAvatarScene"];
[self setupSpritesWithAttachments:self.factory.attachments];
return self.currentScene;
}
...
-(void)setupSpritesWithAttachments:(NSMutableArray *)attachments
{
int i = 0;
//This is where its crashing
for (CCSprite __strong *sprite in self.currentScene.avatar.attachmentSprites) {
CHAttachment *attachment = attachments[i];
sprite.texture = attachment.texture;
i++;
}
}
...
CHCreateAvatarScene
// .h
#import "CCScene.h"
#import "CHAvatar.h"
#interface CHCreateAvatarScene : CCScene
#property (strong, nonatomic) CHAvatar *avatar;
#end
//.m
#import "CHCreateAvatarScene.h"
#implementation CHCreateAvatarScene {
CCNode *avatarNode;
}
-(void)didLoadFromCCB
{
self.avatar = (CHAvatar *)[CCBReader load:#"Avatar"];
[avatarNode addChild:self.avatar];
}
CHAvatar (I don't think its relevant, but included it just in case)
//.h
#import "CCNode.h"
#interface CHAvatar : CCNode
#property (strong, nonatomic) NSMutableArray *attachmentSprites;
#end
//.m
#import "CHAvatar.h"
#implementation CHAvatar {
CCSprite *_shoulders;
CCSprite *_neck;
CCSprite *_head;
}
//Have left off the head for now just to get this working.
-(void)didLoadFromCCB
{
self.attachmentSprites = [#[_shoulders, _neck] mutableCopy];
}
#end
Thanks in advance for any help with this!
The declared type of a variable expresses an intention to the compiler. "I intend to store this type of thing in this storage." The compiler will set aside the proper amount of storage for that type of variable (in this case, a pointer) and it will try to warn about cases where the code is clearly trying to put the wrong type of thing into the variable. But it can only do static checks at compile time. It doesn't put in dynamic checks at run time. It doesn't check what the code is actually doing.
Importantly, the declared type of a pointer variable does not control the actual type of thing being pointed to by any pointer stored into it. Just because you have declared your intent, that doesn't mean your actions (i.e. your code) match that intent.
In your case, the expression [CCBReader loadAsScene:#"CreateAvatarScene"] is actually returning an instance of CCScene, not an instance of CHCreateAvatarScene. You have a type cast to tell the compiler to treat the return value as though it were a pointer to CHCreateAvatarScene. That silences the compiler from complaining, but doesn't actually change the nature of the object the pointer points to.
You wrote in a couple of places that "the view controller thinks" the object is of the wrong class and so can't find the property. This is exactly backward. The code is written to "think" that the object is always of the type CHCreateAvatarScene but it really isn't. The view controller doesn't have to "find" the property. It just acts as though the property exists by calling the getter method. It is the object that has received that message that doesn't know how to respond to it because it's not actually a CHCreateAvatarScene. It's a CCScene object.
The debugger and the error message are both correct about the actual type of the object.
The real question is how +[CCBReader loadAsScene:] works. Why would you expect it to return an instance of CHCreateAvatarScene? Why is it behaving differently than you expect and returning an instance of CCScene?
A friend helped me figure it out, so I'm posting the answer.
Basically, I was mixing up concepts of scenes and nodes in Cocos2d. Here was how I fixed it:
Change CHCreateAvatarViewController's property to type CCScene *currentScene and remove (* CHCreateAvatarScene) casting in the cocosViewControllerSceneToRun: method. In fact, I could probably remove this property all together after this solution is complete.
Rename CHCreateAvatarScene to CHCreateAvatarNode (I was getting mixed up with the concepts of scenes and nodes, so this helped). Change it to be a subclass of CCNode, not CCScene.
Add a CCNode *avatarNode property to the vc. In CCBReaderDidLoad: in the vc, add self.avatarNode = [[CHCreateAvatarNode alloc] init];
In the for loop where the app originally crashed change self.currentScene.avatar.attachmentSprites to self.avatarNode.avatar.attachmentSprites
And voila!

Override UIViewController.view with specific type

Let's consider an application with highly customized or complex views.
We'll have a specific kind of view-controller sending methods to a specific kind of UIView, where the UIView is itself composed of a number of other views.
The view should have a rich, domain-specific interface, allowing the controller to act is a thin "glue" layer between it and a similarly rich model.
So we override our controller's view property as follows:
#interface PlaybackViewController : UIViewController<StageLayoutDelegate, ControlPanelDelegate>
{
NSMutableArray* _sections;
LightingMode _lightingMode;
}
#property (nonatomic, strong) PlaybackView* view; // <------ Specific type of view
#pragma mark - injected
#property (nonatomic, strong) id<OscClient> oscClient;
#property (nonatomic, strong) AbstractStageLayoutView* stageLayoutView;
#end
Ovverriding makes sense over defining another accessor, and I can just send messages to the specific type of UIView without having to cast.
Problem: The only problem is that it results in a compiler warning:
property type 'PlaybackView *' is incompatible with type 'UIView *' inherited from 'UIViewController'
. . and I like to build code that doesn't have any warnings. This way a valid warning doesn't get missed by being buried amongst other warnings.
Question:
Is there a way to suppress this particular warning?
Why is this part of the default settings, when most modern OO languages will happily allow overriding a property or method in a sub-class so that it returns a more specific sub-class of the type declared in the super-class?
The problem here is not not the override of the property, its using a forward declaration of the class type.
So this...
#class PlaybackView;
#interface PlaybackViewController : UIViewController
#property (nonatomic, strong) PlaybackView* view;
#end
will give you the mentioned warning because the compiler cannot know the inheritance hierarchy of PlaybackView. UIViewController has a contract to provide a UIView from its view property
Its telling you that it thinks PlaybackView is not a UIView
The simple solution here is to use a #import instead to give the compiler full knowledge of PlaybackView...
#import "PlaybackView.h"
#interface PlaybackViewController : UIViewController
#property (nonatomic, strong) PlaybackView* view;
#end
alternatively (but really bad form as the PCH is an optimising feature and shouldn't manage dependancies ) is to add #import "PlaybackView.h" to your projects PCH
As suggested in another answer using #import instead of #class will clear the warning but it is advised to import as little as possible in the header, so I would recommend leaving the view unchanged and having an additional PlaybackView * playbackView:
It is perfectly fine to have both view and playbackView pointing to the same view.
Classes that need to have knowledge of your specialized view have to import your controllers header, so they could just use playbackView in the first place.
More important, if you want to embed your specialized view as a subview in the future (which happens often like adding a UIScrollView superview), you won't have to refactor other code and classes!
It's plain cleaner.
I do not think override UIViewControllers view property is a good way .
I think it is better to do like this :
#interface PlaybackViewController : UIViewController<StageLayoutDelegate, ControlPanelDelegate>
{
NSMutableArray* _sections;
LightingMode _lightingMode;
}
//#property (nonatomic, strong) PlaybackView* view; //you do not need this property
#pragma mark - injected
#property (nonatomic, strong) id<OscClient> oscClient;
#property (nonatomic, strong) AbstractStageLayoutView* stageLayoutView;
#end
and in the .m file .
- (void)loadView
{
PlaybackView *mainView = [[PlaybackView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
// set the mainView
self.view = mainView;
}
and you can use your PlaybackView like this .
((PlaybackView *)(self.view)).oscClient
or
((PlaybackView *)(xxxViewControler.view)).oscClient
Perhaps you could declare another method that provides the cast for you, in a sense.
#implementation PlaybackViewController
- (void)viewDidLoad {
[super viewDidLoad];
// use view_ property instead of view
self.view_.foo = 1;
}
- (void)loadView {
CGRect frame = [UIScreen mainScreen].applicationFrame;
self.view = [[PlaybackView alloc] initWithFrame:frame];
}
- (PlaybackView *)view_ {
return (PlaybackView *)self.view;
}
Not exactly the cleanest approach, but it does avoid the cast on self.view (by not using self.view, though)
[UPDATE]
Finally I've probably found a solution that suit the problem:
This is a quick and dirty just to suppress the warning, try to wrap your code between these lines
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
//YOUR CODE
#pragma clang diagnostic pop
or -Wall
To see more about compiler warning suppression Clang Manual
[OLD ANSWER]
I'd like to give my 2 cents.
If I understood well you are trying to create a sort of Abstract factory, that gives you a specialized version of a view based on the view controller funcionality. In my opinion storyboards doesn't work well in that kind of design, but I'd like to give you my vision about it.
First I will create an abstract class for your view controller where in the interface you declare all property you need in all your VC sublcasses, such as :
OSClient
AbstractStageLayoutView
PlaybackView as weak
playbackProperty
The PlaybackView class is a class cluster such as NSNumber, you call a factory method on it, that will return an object that could be different from case to case. If you inspect an NSnumber it returns a different object if you create a float or an integer, but they are all subclasses of NSNumber, and NSNumber declares all the property of its subclasses, but it doesn't implement them.
Now what you can do in the -viewDidLoad method of the abstract class is call a method like that
PlaybackView *plbackView = [PlaybackView playbackViewFroProperty:self.playbackProperty];
[self.view addSubview:playbackView];
self.playbackView = plbackView;
The playbackProperty can be valued inside the User defined runtime attibute in the viewcontroller storyboard editor.

iOS : Other alternative to instance variable?

I have a project which others have written and I have taken over it, hoping to make the app better.
I encountered one problem:
From one class:
I write _customclass.variable. CustomClass is another class and variable is a property and is of int type. And I get value of the variable in this class, but when I change it to self.customclass.variable, I always get 0. Is there other alternative ways to get value from other class?
(a)
#property (readwrite)int boxSpacing;
(b)
#synthesize boxSpacing;
(c)
- (id)initWithCoder:(NSCoder *)aDecoder {
self.boxSpacing = 10;
}
You asked:
Is there other alternative ways to get value from other class?
The short answer is that using the "getter" is the customary way to get a value from another class. But looking at your problem (admitted, not having enough source code to properly diagnose your issue), I'm guessing that the issue rests in the use of instance variables. But more on that later.
First, let's look at the proper use of declared properties and their instance variables and their accessor methods (the getters and setters). Generally you should set properties using these accessor methods. You can, though, use access a variable from within a class using either the instance variable (and you should not use accessor methods in initializer and dealloc methods). And when using the getter and setter, you can choose whether to use the method invocation (e.g. "[self customObject]") or the dot notation (e.g. "self.customObject").
Let's look at an example. Let's assume you have some simple CustomClass:
#interface CustomClass : NSObject
{
// you don't need to declare the instance variable
//int _boxSpacing;
}
#property (nonatomic) int boxSpacing;
#end
#implementation CustomClass
// In Xcode 4.4 and later, the synthesize statement is optional, and if you
// omit it, it will synthesize the instance variable like this, with the
// leading underscore. While you don't need to use an underscore in your
// instance variable, it has become convention in iOS development and it's
// a good technique to minimize chances that you accidentally use the instance
// variable when you actual intended to use the property's accessor methods
// (the getter and setter).
#synthesize boxSpacing = _boxSpacing;
#end
Now, let's assume that you're going to use this CustomClass from within, for example, your view controller. So, first you declare and instance of this CustomClass:
#interface MyViewController : UIViewController
{
// you do not need this instance variable declaration
// the #synthesize statement will take care of this for you
// CustomClass *_customObject;
}
#property (nonatomic, strong) CustomClass *customObject;
#end
And then let's demonstrate how to use the value property of the CustomClass object customObject from within your view controller:
#implementation MyViewController
// Again, in Xcode 4.4 and later, the synthesize statement is optional, and if you
// omit it, it will synthesize the instance variable like this, with the
// leading underscore
#synthesize customObject = _customObject;
- (void)customClassTest
{
// initialize the object
self.customObject = [[CustomClass alloc] init];
// set the property
self.customObject.boxSpacing = 1;
// finally, let's demonstrate three ways to retrieve the value
NSLog(#"%d", self.customObject.boxSpacing);
NSLog(#"%d", [[self customObject] boxSpacing]);
NSLog(#"%d", _customObject.boxSpacing);
// while we're at it, let's demonstrate other ways to set the property
_customObject.boxSpacing = 2;
// or
[[self customObject] setBoxSpacing:3];
}
Ok, so let's get back to your problem. You say:
I write _customclass.variable. CustomClass is another class and variable is a property and is of int type. And I get value of the variable in this class, but when I change it to self.customclass.variable, I always get 0.
Ok, this can be caused by a couple of different problems, but the most common problem I see is confusion between explicitly declared instance variables and the instance variables created behind the scenes by the #synthesize statement. This is why I always advise that people not explicitly define the instance variables for their declared properties, but rather let the #synthesize statement do that automatically. That way I can't have the sort of problem I'm about to demonstrate.
Consider this innocuous (though incorrect) example:
#interface MyViewController : UIViewController
{
CustomClass *_customObject;
}
#property (nonatomic, strong) CustomClass *customObject;
#end
#implementation MyViewController
#synthesize customObject;
- (void)customClassTestError
{
// initialize the object
self.customObject = [[CustomClass alloc] init];
// this works
self.customObject.boxSpacing = 1;
// this doesn't!
_customObject.boxSpacing = 2;
// when it hits this statement, the value will still be 1!!!
NSLog(#"%d", self.customObject.boxSpacing);
}
Do you see the problem? While I declared an instance variable with the underscore, _customObject, when the compiler hit the #synthesize statement, it created another instance variable, this time without the leading underscore, customObject. Thus, my explicitly declared instance variable never received the init/alloc and therefore is nil and thus any attempts to use it won't work!
Typically we see the converse problem (an explicitly declared instance variable without the underscore and a #synthesize statement of the form #synthesize customObject = _customObject), but hopefully you'll get the idea.
Anyway, this is the most common example of what would cause the behavior you describe. If this isn't what's going on, please provide us a more extensive code sample.
But if you're having problems, I'd always suggest that you check the value of your CustomClass object, itself, before you try to access its properties. Make sure the class object itself has been properly initialized (whether for the reasons I list above, or some other initialization problem) before you try to use its properties. You can do something like NSLog(#"CustomClass object = %#", customObject); or NSAssert(customObject, #"Object not properly initialized");.
Have you defined a #property for the CustomClass? If so, have you assigned a value?
If not, then you're sending the message variable to nil. And in your case that will result to 0.

Resources