Advertise Mobile SDKs Books Events Forum News Social Networking Support Us
Follow @iphonedevsdk on Twitter

Interface 2, Advanced iOS
Mockup & Code Gen
($9.99)

Make your own iPhone apps
and run them live!
(free)

Pic Frame Dynamo: Photo Editing
($0.99)

Abiliator
($1.99)

Want your application or service advertised on iPhone Dev SDK?

Go Back   iPhone Dev SDK Forum > iPhone SDK Development Forums > iPhone SDK Development

Reply
 
LinkBack Thread Tools Display Modes
Old 09-15-2011, 01:46 AM   #1 (permalink)
Registered Member
 
Join Date: Aug 2011
Posts: 9
skot is on a distinguished road
Default @synthesize with implicit ivar: strange inheritance behavior

When I try to compile the code below I get build failed with "baseClassVar" undeclared (first use in this function)
at the line marked "error occurs here".

(baseClassVar is an ivar in the superclass, which should be visible to the subclass.)

But if I uncomment the explicit ivar declaration for "subclassVar" (line 11), the code compiles without complaint.

In other words, if the subclass has an implicit ivar, it can't see the (unrelated) explicit ivars of the superclass!

What the?

Any idea what's going on here?


Code:
@interface BaseClass : NSObject {
  NSString *baseClassVar;
}
@end

@implementation BaseClass
@end


@interface Subclass : BaseClass {
  //NSString *subclassVar; // <-- uncomment this and it compiles fine
}
@property (nonatomic, retain) NSString *subclassVar;
@end

@implementation Subclass
@synthesize subclassVar;
- (void)aMethod { 
  baseClassVar = @"something"; // <-- error occurs here: "baseClassVar" undeclared (first use in this function)
}
@end
skot is offline   Reply With Quote
Old 09-15-2011, 06:07 AM   #2 (permalink)
Emphasizing Fundamentals
 
BrianSlick's Avatar
 
Join Date: Jul 2009
Location: NoVA / DC Area
Age: 36
Posts: 7,990
BrianSlick has a spectacular aura about
Default

1. Don't use ivars. Problem solved.

2. Implicit ivars means you don't declare them explicitly, but get them via the synthesized property. That's not what you're doing.

3. There is an arrow notation that might work here, something like self->baseClassVar, but I never use it so don't know much about it.

4. Why would you declare the ivar and property in different classes?

5. See #1.
__________________
BriTer Ideas LLC - Professional iOS App Development. Available for hire.

SlickShopper 2 | Free NSLog utility | Leave a PayPal donation.

Are you a newbie? Things you should read:
Definitive Guide To Properties | UITableView Series | Guide To Troubleshooting | Model Object Overview

Do you sit at a desk all day? Walk instead! Follow along with my treadmill desk adventures.
BrianSlick is offline   Reply With Quote
Old 09-15-2011, 07:28 AM   #3 (permalink)
Registered Member
 
Join Date: Nov 2008
Posts: 864
nobre84 is on a distinguished road
Default

What compiler are you using ? GCC had problems with this scenario, LLVM 2.0 will work flawlessly this way as far as I know.
nobre84 is offline   Reply With Quote
Old 09-15-2011, 10:57 AM   #4 (permalink)
Registered Member
 
Join Date: Aug 2011
Posts: 9
skot is on a distinguished road
Default

@BrianSlick:

1. I was looking for protected behavior, ie, I want a value that's readonly from the outside but readwrite to subclasses. AFAICT after searching, this can't be done with properties.

2. If you look again you'll see there are two ivars, an explicit one (baseClassVar) in BaseClass and an implicit one (subclassVar) in Subclass. The complier stops complaining about the BaseClass ivar when I change the Subclass ivar from implicit to explicit.

4. See #2: Again I think you're confusing the two ivars. The property subclassVar, declared in Subclass, should have nothing to do with the ivar baseclassVar, declared in BaseClass.

5. Actually I would prefer to use only properties, but I don't like how that pretty much forces you to make all your values public readwrite. (What is a readonly property anyway if you never directly reference the underlying ivar? How do you set it?)

but

3. Actually, this is a real solution. It turns out that changing baseClassVar = @"something" to self->baseClassVar = @"something" makes the code compile.

Last edited by skot; 09-15-2011 at 11:01 AM.
skot is offline   Reply With Quote
Old 09-15-2011, 11:47 AM   #5 (permalink)
Registered Member
 
Join Date: Nov 2008
Posts: 864
nobre84 is on a distinguished road
Default

I confirmed that this only fails using GCC 4.2; LLVM GCC and LLVM 2.0 works fine on this situation. I don't think there's any reason to use GCC 4.2 anymore, all issues regarding older devices are fixed since XCode 4.0.1
BTW You can re-define properties in a private category, allowing you to make it publicly readonly, but privately readwrite, like this (compiles fine on either GCC4.2 or newer compilers)
Code:
@interface MyClass : NSObject {
}
@property (nonatomic, retain, readonly) NSString *baseClassVar;
@end

@interface MySubClass : MyClass {
}
@property (nonatomic, retain) NSString *subclassVar;
@end



@interface MyClass ()
@property (nonatomic, retain, readwrite) NSString *baseClassVar;
@end


@implementation MyClass
@synthesize baseClassVar;
@end

@implementation MySubClass
@synthesize subclassVar;
- (void)aMethod { 
    self.baseClassVar = @"something"; // <-- error occurs here: "baseClassVar" undeclared (first use in this function)
}
@end

Last edited by nobre84; 09-15-2011 at 11:51 AM.
nobre84 is offline   Reply With Quote
Old 09-15-2011, 02:46 PM   #6 (permalink)
Registered Member
 
Join Date: Aug 2011
Posts: 9
skot is on a distinguished road
Default

@nobre84

Yes, you're right the LLVM compiler doesn't choke on this. Thanks!

And yes, redefining properties in a private category looks like the way to go. But if you want protected properties, ie properties that subclasses can write, you have to put them in a separate header file. Each subclass (and the base class implementation file!) will have to import this new header file and also re-@synthesize the property.

Code:
BaseClass.h:
@interface BaseClass : NSObject
@property (nonatomic, readwrite) NSString *publicVar;
@property (nonatomic, readonly) NSString *privateVar;
@property (nonatomic, readonly) NSString *protectedVar;
@end

BaseClass+Protected.h:
import "BaseClass.h"
@interface BaseClass (Protected)
@property (nonatomic, retain, readwrite) NSString *protectedVar;
@end

BaseClass.m:
#import BaseClass+Protected.h
@interface BaseClass (Private)
@property (nonatomic, retain, readwrite) NSString *privateVar;
@end

@implementation BaseClass
@synthesize publicVar;
@synthesize privateVar;
@synthesize protectedVar;
@end

Subclass.h:
#import "BaseClass+Protected.h"
@interface Subclass : BaseClass
@end

Subclass.m:
#import Subclass.h
@implementation Subclass
@synthesize protectedVar;
@end
This seems like a lot of work to get properties to do something ivars do for free.

Or I suppose you could redo the @property declarations in every subclass that needs to access them. Then you avoid the extra BaseClass+Protected.h header file, the tradeoff being you have to rewrite the @property declarations in every subclass (and the @synthesize statements too, but you were rewriting those already).

Code:
BaseClass.h:
@interface BaseClass : NSObject
@property (nonatomic, readwrite) NSString *publicVar;
@property (nonatomic, readonly) NSString *privateVar;
@property (nonatomic, readonly) NSString *protectedVar;
@end

BaseClass.m:
#import BaseClass.h
@interface BaseClass (Private)
@property (nonatomic, retain, readwrite) NSString *privateVar;
@property (nonatomic, retain, readwrite) NSString *protectedVar;
@end

@implementation BaseClass
@synthesize privateVar;
@synthesize protectedVar;
@end

Subclass.h:
#import "BaseClass.h"
@interface Subclass : BaseClass
@end

Subclass.m:
#import "Subclass.h"
@interface Subclass (Private)
@property (nonatomic, retain, readwrite) NSString *protectedVar;
@end

@implementation Subclass
@synthesize protectedVar;
@end
It's disheartening that so much bookkeeping is required just to accomplish what the keyword "protected" provides in java. Is anybody really doing this when they write subclasses? My guess is they either access the ivars directly or they've given up on protecting their properties at all, and code everything readwrite.

Last edited by skot; 09-15-2011 at 04:57 PM.
skot is offline   Reply With Quote
Old 09-15-2011, 04:21 PM   #7 (permalink)
Registered Member
 
Join Date: Nov 2008
Posts: 864
nobre84 is on a distinguished road
Default

Oh, I see. I have used the ivar approach for subclasses too.
I'm not sure declaring it in another file would even work, if you override the property anywhere outside of the main class implementation wouldn't it require a separate @implementation for the category, that would in turn need to access the ivar directly? Too much trouble indeed
nobre84 is offline   Reply With Quote
Reply

Bookmarks

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



» Advertisements
» Online Users: 406
16 members and 390 guests
7twenty7, Eclectic, eski, EvilElf, fiftysixty, HemiMG, iOS.Lover, JackReidy, jarv, Pudding, sacha1996, teebee74, tim0504, UMAD, VinceYuan, yuncarl28
Most users ever online was 1,387, 04-10-2012 at 04:21 AM.
» Stats
Members: 175,672
Threads: 94,121
Posts: 402,905
Top Poster: BrianSlick (7,990)
Welcome to our newest member, yuncarl28
Powered by vBadvanced CMPS v3.1.0

All times are GMT -5. The time now is 05:10 AM.
Powered by vBulletin® Version 3.8.0
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.3.0