@interface 或 @implementation 中的私有 ivar

发布于 2024-12-26 16:26:31 字数 782 浏览 1 评论 0原文

是否有任何理由在 @interface 中声明私有 ivar 而不是 @implementation

我在互联网上看到这样的代码(包括 Apple):

Foo.h

@interface Foo : NSObject {
@private
    id _foo;
}
@end

Foo.m

@implementation Foo
// do something with _foo
@end

头文件定义类的公共接口,而私有 ivar 是...嗯……私人的。那么为什么不这样声明呢?

Foo.h

@interface Foo : NSObject
@end

Foo.m

@implementation Foo {
@private
    id _foo;
}

// do something with _foo
@end

Is there any reason to declare a private ivar in @interface instead of @implementation?

I see code like this all over the internet (including documentation provided by Apple):

Foo.h

@interface Foo : NSObject {
@private
    id _foo;
}
@end

Foo.m

@implementation Foo
// do something with _foo
@end

The header file defines the public interface of a class, whereas a private ivar is... well... private. So why not declare it like this?

Foo.h

@interface Foo : NSObject
@end

Foo.m

@implementation Foo {
@private
    id _foo;
}

// do something with _foo
@end

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

浪漫之都 2025-01-02 16:26:31

@implementation 中声明实例变量是 Obj-C 的一项最新功能,这就是为什么您在 @interface 中看到大量带有它们的代码 - 没有其他选择。

如果您使用的编译器支持在声明实现中声明实例变量,则可能有最好的默认设置 - 仅当其他人需要访问它们时才将它们放入接口中。

编辑:附加信息

在实现中声明的实例变量隐式隐藏(实际上是私有的)并且可见性无法更改 - @public@protected@private 不会产生编译器错误(至少对于当前的 Clang 而言),但会被忽略。

Declaring instance variables in the @implementation is a recent feature of Obj-C, this is why you see a lot of code with them in the @interface - there was no other choice.

If you are using a compiler which supports declaring instance variables in the implementation declaring them there is probably the best default - only put them in the interface if they need to be accessed by others.

Edit: Additional Info

Instance variables declared in the implementation are implicitly hidden (effectively private) and the visibility cannot be changed - @public, @protected and @private do not produce compiler errors (with the current Clang at least) but are ignored.

小嗲 2025-01-02 16:26:31

如果您需要针对旧系统或 Xcode 版本的编译器支持,您会喜欢 @interface

如果您确定不需要向后兼容性,我建议最好将其放在 @implementation 中。

  • 我认为@private 是一个很好的默认值。
  • 如果使用得当,它可以最大限度地减少编译时间并减少依赖性。
  • 您可以减少标题顶部的大部分噪音。许多人会为其 ivars 添加 #imports,但他们应该使用前向声明作为默认值。因此,您可以从标头中删除许多 #import 和许多前向声明。

You would favor @interface if you need compiler support targeting older systems or releases of Xcode.

If you are certain you will not need that backwards compatibility, I'd say it's best to place it in the @implementation.

  • I think @private is a good default.
  • It minimizes compile times, and reduces dependencies if you use it right.
  • You can reduce much of that noise at the top of your header. Many people will put #imports for their ivars, but they should use a forward declaration as default. So you can remove many #imports and many forward declarations from your header.
落在眉间の轻吻 2025-01-02 16:26:31

指令@public、@protected 和@private 是
不绑定在 Objective-C 中,它们是编译器提示
变量的可访问性。
它不会限制您访问它们。

示例:

@interface Example : Object
{
@public
int x;
@private
int y;
}
...


...
id ex = [[Example alloc ] init];
ex->x = 10;
ex->y = -10;
printf(" x = %d , y = %d \n", ex->x , ex->y );
...

gcc 编译器会输出:

Main.m:56:1:警告:实例变量“y”是@private;这将是未来的一个硬错误

Main.m:57:1:警告:实例变量“y”是@private;这将是未来的一个硬错误

对于每个对“私有”成员 y 的“不适当”访问,

,但无论如何都会编译它。当运行时,你会得到

x = 10 , y = -10

So it确实取决于你不以这种方式编写访问代码,但因为 objc 是 C 的超集
C 语法工作得很好,并且所有类都是透明的。

您可以设置编译器将这些警告视为错误并进行保释——但 Objective-C 内部并未针对这种严格性进行设置。动态方法分派必须检查每个调用的范围和权限(slooooowwwww...),因此除了编译时警告之外,系统还希望程序员尊重数据成员范围。

在 Objective-C 中,有几种获取成员隐私的技巧。
一是确保将类的接口和实现分别放在单独的 .h 和 .m 文件中,并将数据成员放在实现文件(.m 文件)中。
那么导入头文件的文件就无法访问数据成员,只能访问类本身。
然后在标头中提供访问方法(或不)。您可以实现 setter/getter 函数
如果您愿意,可以在用于诊断目的的实现文件中,并且它们将是可调用的,
但不能直接访问数据成员。

示例:

@implementation Example2 :Object
{ 
 //nothing here
}
double hidden_d; // hey now this isn't seen by other files.
id classdata;    // neither is this.

-(id) classdata { return [classdata data]; } // public accessor
-(void) method2 { ... }
@end

// this is an "informal category" with no @interface section
// these methods are not "published" in the header but are valid for the class

@implementation Example2 (private)
-(void)set_hidden_d:(double)d { hidden_d = d; }

// You can only return by reference, not value, and the runtime sees (id) outside this file.
// You must cast to (double*) and de-reference it to use it outside of this file. 
-(id) hidden_d_ptr { return &hidden_d;}
@end

...
[Main.m]
...
ex2 = [[Example2 alloc] init];

double d = ex2->hidden_d; // error: 'struct Example2’ has no member named ‘hidden_d’
id data = ex2->classdata; // error: 'struct Example2’ has no member named ‘classdata’
id data = [ex2 classdata] // OK

[ex2 set_hidden_d : 6.28318 ]; // warning:'Example2' may not respond to '-set_hidden_d:'

double* dp = [ex2 hidden_d_ptr]; // (SO UGLY)  warning: initialization from incompatible pointer type
                                 // use (double*)cast -- <pointer-to-pointer conversion>  
double d = (*dp); // dereference pointer (also UGLY). 

...

编译器将对这种公然的恶作剧发出警告,但会继续
并相信你知道自己在做什么(真的吗?),并且你有自己的理由(是吗?)。
看起来工作量很大?容易出错?耶宝贝!
在使用神奇的 C 技巧和像这样的肉丸手术之前,请先尝试重构代码。

但它就在那里。祝你好运。

The directives @public, @protected, and @private are
not binding in objective-C, they are compiler hints about
the accessibility of the variables.
It DOES NOT RESTRICT YOU from accessing them.

example:

@interface Example : Object
{
@public
int x;
@private
int y;
}
...


...
id ex = [[Example alloc ] init];
ex->x = 10;
ex->y = -10;
printf(" x = %d , y = %d \n", ex->x , ex->y );
...

The gcc compiler spits out :

Main.m:56:1: warning: instance variable ‘y’ is @private; this will be a hard error in the future

Main.m:57:1: warning: instance variable ‘y’ is @private; this will be a hard error in the future

once for each "innapropriate" access to "private" member y, but compiles it anyway.

When run you get

x = 10 , y = -10

So it really is up to you NOT to write access code this way, but because objc is a superset of C,
C syntax works just fine, and all classes are transparent.

You can set the compiler to treat these warnings as errors and bail -- but objective-C is not set up internally for this kind of strictness. The dynamic method dispatch would have to check for scope and permission for each call ( slooooowwwww... ) , so beyond a compile-time warning, the system expects the programmer to respect data member scoping.

There are several tricks to getting privacy of members in objective-C.
One is to make sure you put the interface and implementations of your class in separate .h and .m files, respectively, and put the data members in the implementation file (the .m file).
Then the files that import the headers do not have access to the data members, only the class itself.
Then provide access methods (or not) in the header. You can implement setter/getter functions
in the implementation file for diagnostic purposes if you want and they will be callable,
but direct access to the data members will not be.

example:

@implementation Example2 :Object
{ 
 //nothing here
}
double hidden_d; // hey now this isn't seen by other files.
id classdata;    // neither is this.

-(id) classdata { return [classdata data]; } // public accessor
-(void) method2 { ... }
@end

// this is an "informal category" with no @interface section
// these methods are not "published" in the header but are valid for the class

@implementation Example2 (private)
-(void)set_hidden_d:(double)d { hidden_d = d; }

// You can only return by reference, not value, and the runtime sees (id) outside this file.
// You must cast to (double*) and de-reference it to use it outside of this file. 
-(id) hidden_d_ptr { return &hidden_d;}
@end

...
[Main.m]
...
ex2 = [[Example2 alloc] init];

double d = ex2->hidden_d; // error: 'struct Example2’ has no member named ‘hidden_d’
id data = ex2->classdata; // error: 'struct Example2’ has no member named ‘classdata’
id data = [ex2 classdata] // OK

[ex2 set_hidden_d : 6.28318 ]; // warning:'Example2' may not respond to '-set_hidden_d:'

double* dp = [ex2 hidden_d_ptr]; // (SO UGLY)  warning: initialization from incompatible pointer type
                                 // use (double*)cast -- <pointer-to-pointer conversion>  
double d = (*dp); // dereference pointer (also UGLY). 

...

The compiler will issue warnings for such blatant shenanigans, but will go ahead
and trust that you know what you are doing (really?), and that you have your reasons (do you?).
Seem like a lot of work? Error Prone? Yay Baby!
Try refactoring your code first before resorting to magic C tricks and meatball surgery like this.

But there it is. Good luck.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文