将iVars放在哪里?目标-C? [英] Where to put iVars in "modern" Objective-C?

查看:71
本文介绍了将iVars放在哪里?目标-C?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Ray Wenderlich撰写的《 iOS6 by Tutorials》一书中有一章非常不错,它写了更多现代" Objective-C代码.在其中的一小节中,这些书描述了如何将iVars从类的标题移到实现文件中. 由于所有iVar都应该是私有的,因此这似乎是正确的选择.

The book "iOS6 by Tutorials" by Ray Wenderlich has a very nice chapter about writing more "modern" Objective-C code. In one section the books describes how to move iVars from the header of the class into the implementation file. Since all iVars should be private this seems to be the right thing to do.

但是到目前为止,我发现了三种方法.每个人的做法都不同.

But so far I found 3 ways of doing so. Everyone is doing it differently.

1.)将iVars放在大括号内的@implementantion下(这是本书中的做法).

1.) Put iVars under @implementantion inside a block of curly braces (This is how it is done in the book).

2.)将iVars放在@implementantion下,没有大括号括起来

2.) Put iVars under @implementantion without block of curly braces

3.)将iVars放在@implementantion(类扩展名)上方的专用接口内

3.) Put iVars inside private Interface above the @implementantion (a class extension)

所有这些解决方案似乎都可以正常工作,到目前为止,我还没有注意到我的应用程序的行为有什么不同. 我猜没有做到这一点的正确"方法,但是我需要写一些教程,我只想为我的代码选择一种方法.

All these solutions seems to work fine and so far I haven't noticed any difference in the behavior of my application. I guess there is no "right" way of doing it but I need to write some tutorials and I want to choose only one way for my code.

我应该走哪条路?

我在这里只谈论iVars.不是属性.对象仅需要自身的其他变量,并且不应暴露在外部.

代码示例

1)

#import "Person.h"

@implementation Person
{
    int age;
    NSString *name;
}

- (id)init
{
    self = [super init];
    if (self)
    {
        age = 40;
        name = @"Holli";
    }
    return self;
}
@end

2)

#import "Person.h"

@implementation Person

int age;
NSString *name;


- (id)init
{
    self = [super init];
    if (self)
    {
        age = 40;
        name = @"Holli";
    }
    return self;
}
@end

3)

#import "Person.h"

@interface Person()
{
    int age;
    NSString *name;
}
@end

@implementation Person

- (id)init
{
    self = [super init];
    if (self)
    {
        age = 40;
        name = @"Holli";
    }
    return self;
}
@end

推荐答案

将实例变量放入@implementation块或类扩展中的能力是现代Objective-C运行时"的一项功能,该功能每个版本的iOS以及64位Mac OS X程序都使用该程序.

The ability to put instance variables in the @implementation block, or in a class extension, is a feature of the "modern Objective-C runtime", which is used by every version of iOS, and by 64-bit Mac OS X programs.

如果要编写32位Mac OS X应用程序,则必须将实例变量放在@interface声明中.不过,您可能不需要支持应用程序的32位版本.自五年前发布的10.5版(Leopard)以来,OS X已支持64位应用程序.

If you want to write 32-bit Mac OS X apps, you must put your instance variables in the @interface declaration. Chances are you don't need to support a 32-bit version of your app, though. OS X has supported 64-bit apps since version 10.5 (Leopard), which was released over five years ago.

因此,假设您仅在编写将使用现代运行时的应用程序.您应该将ivars放在哪里?

So, let's assume you are only writing apps that will use the modern runtime. Where should you put your ivars?

首先,让我们看看为什么我们要在@interface声明中放置实例变量.

First, let's go over why we don't want to put instance variables in an @interface declaration.

  1. 将实例变量放入@interface中可向类用户公开实现的详细信息.这可能会导致这些用户(甚至在使用自己的类时甚至是您自己!)也要依赖他们不应使用的实现细节. (这与我们是否声明Ivars @private是无关的.)

  1. Putting instance variables in an @interface exposes details of the implementation to users of the class. This may lead those users (even yourself when using your own classes!) to rely on implementation details that they should not. (This is independent of whether we declare the ivars @private.)

将实例变量放入@interface中会使编译花费更长的时间,因为每次添加,更改或删除ivar声明时,我们都必须重新编译每个导入接口的.m文件.

Putting instance variables in an @interface makes compiling take longer, because any time we add, change, or remove an ivar declaration, we have to recompile every .m file that imports the interface.

所以我们不想将实例变量放在@interface中.我们应该把它们放在哪里?

So we don't want to put instance variables in the @interface. Where should we put them?

接下来,让我们讨论您的选项2,将iVars放在@implementantion下,不要使用花括号."这不会声明实例变量!您正在谈论这个:

Next, let's discuss your option 2, "Put iVars under @implementantion without block of curly braces". This does not declare instance variables! You are talking about this:

@implementation Person

int age;
NSString *name;

...

该代码定义了两个全局变量.它不声明任何实例变量.

That code defines two global variables. It does not declare any instance variables.

如果需要全局变量,则可以在.m文件中甚至在@implementation中定义全局变量,例如,因为您希望所有实例共享某些状态(例如缓存),因此很好.但是您不能使用此选项声明ivars,因为它没有声明ivars. (此外,通常应将实现专用的全局变量声明为static,以避免污染全局名称空间并冒链接时错误的风险.)

It's fine to define global variables in your .m file, even in your @implementation, if you need global variables - for example, because you want all of your instances to share some state, like a cache. But you can't use this option to declare ivars, because it doesn't declare ivars. (Also, global variables private to your implementation should usually be declared static to avoid polluting the global namespace and risking link-time errors.)

剩下的选项1和3.

通常,我们要使用选项1:将它们放在大括号内的主@implementation块中,如下所示:

Usually we want to use option 1: put them in your main @implementation block, in braces, like this:

@implementation Person {
    int age;
    NSString *name;
}

之所以将它们放在这里是因为它将它们的存在保密,从而防止了我前面描述的问题,并且通常没有理由将它们放在类扩展中.

We put them here because it keeps their existence private, preventing the problems I described earlier, and because there's usually no reason to put them in a class extension.

那么我们何时要使用选项3,将其放在类扩展中?

So when do we want to use your option 3, putting them in a class extension?

几乎没有理由将它们放在与类@implementation相同的文件中的类扩展中.在这种情况下,我们也可以将它们放在@implementation中.

There's almost never a reason to put them in a class extension in the same file as the class's @implementation. We might as well just put them in the @implementation in that case.

但是有时候我们可能会编写一个足够大的类,以便将其源代码分成多个文件.我们可以使用类别来做到这一点.例如,如果我们正在实现UICollectionView(一个相当大的类),我们可能会决定要将管理可重用视图(单元格和补充视图)队列的代码放在单独的源文件中.我们可以通过将这些消息分成一个类别来做到这一点:

But occasionally we might write a class that's big enough that we want to divide up its source code into multiple files. We can do that using categories. For example, if we were implementing UICollectionView (a rather big class), we might decide that we want to put the code that manages the queues of reusable views (cells and supplementary views) in a separate source file. We could do that by separating out those messages into a category:

// UICollectionView.h

@interface UICollectionView : UIScrollView

- (id)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
@property (nonatomic, retain) UICollectionView *collectionViewLayout;
// etc.

@end

@interface UICollectionView (ReusableViews)

- (void)registerClass:(Class)cellClass forCellWithReuseIdentifier:(NSString *)identifier;
- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier;

- (void)registerClass:(Class)viewClass forSupplementaryViewOfKind:(NSString *)elementKind withReuseIdentifier:(NSString *)identifier;
- (void)registerNib:(UINib *)nib forSupplementaryViewOfKind:(NSString *)kind withReuseIdentifier:(NSString *)identifier;

- (id)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath*)indexPath;
- (id)dequeueReusableSupplementaryViewOfKind:(NSString*)elementKind withReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath*)indexPath;

@end

好的,现在我们可以在UICollectionView.m中实现主要的UICollectionView方法,并且可以在UICollectionView+ReusableViews.m中实现管理可重用视图的方法,这使我们的源代码更易于管理.

OK, now we can implement the main UICollectionView methods in UICollectionView.m and we can implement the methods that manage reusable views in UICollectionView+ReusableViews.m, which makes our source code a little more manageable.

但是我们的可重用视图管理代码需要一些实例变量.这些变量必须公开给UICollectionView.m中的主类@implementation,因此编译器将在.o文件中发出它们.并且我们还需要将这些实例变量公开给UICollectionView+ReusableViews.m中的代码,以便这些方法可以使用ivars.

But our reusable view management code needs some instance variables. Those variables have to be exposed to the main class @implementation in UICollectionView.m, so the compiler will emit them in the .o file. And we also need to expose those instance variables to the code in UICollectionView+ReusableViews.m, so those methods can use the ivars.

这是我们需要类扩展的地方.我们可以将reusable-view-management ivars放在私有头文件的类扩展中:

This is where we need a class extension. We can put the reusable-view-management ivars in a class extension in a private header file:

// UICollectionView_ReusableViewsSupport.h

@interface UICollectionView () {
    NSMutableDictionary *registeredCellSources;
    NSMutableDictionary *spareCellsByIdentifier;

    NSMutableDictionary *registeredSupplementaryViewSources;
    NSMutableDictionary *spareSupplementaryViewsByIdentifier;
}

- (void)initReusableViewSupport;

@end

我们不会将此头文件发送给我们库的用户.我们将其导入到UICollectionView.mUICollectionView+ReusableViews.m中,以便所有需要 来查看这些ivars的人都可以看到它们.我们还抛出了一个方法,我们希望调用主init方法来初始化可重用视图管理代码.我们将在UICollectionView.m中的-[UICollectionView initWithFrame:collectionViewLayout:]中调用该方法,并在UICollectionView+ReusableViews.m中实现它.

We won't ship this header file to users of our library. We'll just import it in UICollectionView.m and in UICollectionView+ReusableViews.m, so that everything that needs to see these ivars can see them. We've also thrown in a method that we want the main init method to call to initialize the reusable-view-management code. We'll call that method from -[UICollectionView initWithFrame:collectionViewLayout:] in UICollectionView.m, and we'll implement it in UICollectionView+ReusableViews.m.

这篇关于将iVars放在哪里?目标-C?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆