English 中文(简体)
Circular #import/@class problem in ObjectiveC
原标题:

I m going to use an example to properly illustrate my confusion. I can t quite wrap my head around this.

In Cocoa touch, we have UIViewController and its subclass, UINavigationController. Now, UIVC has an ivar of type UINav, and to get around the circular import problem they use @class UINavigationController. I am assuming they then #import "UINavigationController in UIViewController.m (or somesuch).

My confusion is thus: How do subclasses of UIViewController then know about the methods declared in UINavigationController? From inside a UIViewController subclass one might call [self.navigationController popViewController], but how is that method known?

The only idea I have is UINavigationController must be separately imported to every subclass (perhaps in the prefix?)

Any ideas?

最佳回答

If this project was created with one of the Xcode templates, then the headers for all the classes in the UIKit are probably being included from the pre-compiled header of the project.

问题回答

It s not imported headers hidden away. Subclass "know" everything the super class "knows". This is one of the strengths of a single inheritance design. Consider 3 classes;

ClassA.h

#import <Foundation/Foundation.h>

@class ClassB;
@interface ClassA : NSObject {
    ClassB *bClass;
}
@property(nonatomic, retain)  ClassB *bClass;

@end

ClassA.m

#import "ClassA.h"
#import "ClassB.h"

@implementation ClassA
@synthesize bClass;

-(ClassB *) bClass{
    return [[ClassB alloc] init];
}
@end

ClassB:

#import <Foundation/Foundation.h>

@class ClassA;
@interface ClassB : NSObject {
    ClassA *aClass;
    NSString *name;
}
@property(nonatomic, retain)  ClassA *aClass;
@property(nonatomic, retain)  NSString *name;

@end

ClassB.m

#import "ClassB.h"
#import "ClassA.h"

@implementation ClassB
@synthesize aClass;
@synthesize name;

-(NSString *) name { return @"steve";}
@end

Now create a subclass of ClassA: ClassC.h

#import <Foundation/Foundation.h>
#import "ClassA.h"

@interface ClassC : ClassA {

}

@end

ClassC.m

#import "ClassC.h"
@implementation ClassC

@end

When you call ClassC s bclass s name method:

#import "ClassC.h"
...
ClassC *c=[[ClassC alloc] init];
NSLog(@"c %@",[[c bClass] name]); //prints "c steve"

Subclasses inherent the headers imported in their super classes implementation file.

Edit01:

From the comments:

Try this: Define a macro in ClassA.h, then try to use that macro in ClassC.m (without importing ClassA.h there). It won t compile

In all due respect, I think this is incorrect. The below is actual code that compiles and runs:

ClassA.h

#import <Foundation/Foundation.h>

#define aMacro 5

@class ClassB;
@interface ClassA : NSObject {
    ClassB *bClass;
}
@property(nonatomic, retain)  ClassB *bClass;   
@end

ClassC.h

#import <Foundation/Foundation.h>
#import "ClassA.h"

@interface ClassC : ClassA {
}
-(void) logMacro;
@end

ClassC.m

#import "ClassC.h"

@implementation ClassC
-(void) logMacro{
    NSLog(@"aMacro=%d",aMacro);
}//-------------------------------------(void) logMacro------------------------------------
@end

When run:

#import "ClassC.h" //the only header imported of the three classes ./////////
...
ClassC *c=[[ClassC alloc] init];
NSLog(@"c %@",[[c bClass] name]);
[c logMacro]; //prints 5

Clearly, ClassC.m knows about a macro defined in ClassA.h based solely on importing ClassA.h in ClassC.h (which as a subclass it must do).

ClassC won t know about a macro defined in ClassA.m but that is because a macro defined in an implementation isn t actually a logical part of the class. ClassA doesn t know about the macro either. Such a macro is not in the class s name space, it s just a simple text substitution performed by the compiler. ClassC doesn t know about such substitutions anymore than it knows that ClassA used an actual 5 somewhere in one of its methods. ClassC can t inherent such a macro because there is nothing to inherent.

ClassC knows about macros defined in ClassA because the true logical header for ClassC that the compiler generates is the union of all the headers in the chain created by the imports. ClassC knows everything ClassA knows just like it knows everything that the Foundation framework knows.

ClassC knows about ClassB the same way that ClassA does. The @class directive causes the compiler to look forward for the definition of ClassB and it finds it in the ClassA.m. There is no secret importing of masses of header files behind the scenes. That was the question poised in the parent.





相关问题
Oracle: how to disable table compression on dmp file import

I have dmp file that was created by EXP utility. The source database has table compression enabled. How can I disable compression while importing dmp file. The destination database does not have ...

import feedparser works via SSH, but fails when in browser

I installed feedparser via SSH, using $ python setup.py install --home=~/httpdocs/python-libraries/feedparser-4.1/ I did that because I don t seem to have permission to properly run python setup.py ...

How to import existing ROR project?

I m new to Ruby on Rails (PHP developer here) and I need to edit an existing ROR project. I ve been using Aptana Studio for my PHP projects (switched to Zend after Aptana 2.0) but I ve kept Aptana ...

Circular #import/@class problem in ObjectiveC

I m going to use an example to properly illustrate my confusion. I can t quite wrap my head around this. In Cocoa touch, we have UIViewController and its subclass, UINavigationController. Now, UIVC ...

C# GemBox Excel Import Error

I am trying to import an excel file into a data table using GemBox and I keep getting this error: Invalid data value when extracting to DataTable at SourceRowIndex: 1, and SourceColumnIndex: 1. As ...

Importing from excel "applications" using SSIS

I am looking for any tips or resources on importing from excel into a SQL database, but specifically when the information is NOT in column and row format. I am currently doing some pre-development ...

热门标签