xcode 将 Objective-C 代码拆分成多个文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13357775/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 02:04:44  来源:igfitidea点击:

Split Objective-C Code into multiple files

objective-cxcode

提问by Naveed Abbas

I often feel the need to split the Objective-C code into multiple files for better readability. I want to avoid making classes and call them. I want simple import (like in php).

我经常觉得需要将 Objective-C 代码拆分成多个文件以提高可读性。我想避免上课并打电话给他们。我想要简单的导入(就像在 php 中一样)。

If someone could please refer a working example.

如果有人可以请参考一个工作示例。

回答by Kaan Dedeoglu

I think you're looking at categories in this case:

我认为在这种情况下您正在查看类别:

All you have to do is to create a new .h .m pair and in the .h file:

您所要做的就是在 .h 文件中创建一个新的 .h .m 对:

#import MyClass.h

@interface MyClass(Networking)

//method declarations here

@end

and in the .m file:

并在 .m 文件中:

#import MyClass+Networking.h

@implementation MyClass(Networking)

//method definitions here

@end

And in MyClass.m file - do #import MyClass+Networking.h and you're all set. This way you can extend your class.

在 MyClass.m 文件中 - 执行 #import MyClass+Networking.h 就可以了。这样你就可以扩展你的类。

回答by rob mayoff

You say “I want to avoid making classes and call them.” You need to overcome your fear of adding classes. If you feel the need to split a class's implementation into multiple files, chances are you are trying to do too much in a single class. You need to let that class hand off (“delegate”) some responsibilities to other classes.

你说“我想避免上课并打电话给他们。” 您需要克服对添加类恐惧。如果您觉得需要将一个类的实现拆分成多个文件,那么您很可能试图在单个类中做太多事情。您需要让该类将某些职责移交(“委托”)给其他类。

That said, there are a couple of ways you can split up a class's implementation. The better way, short of fixing your bloated class design, is to use categories or class extensions. You can read all about categories and extensions in The Objective-C Programming Language. Note that the linker will merge the categories and extensions into the class when it creates your executable file, so there's no runtime penalty for using categories or extensions on your own classes.

也就是说,有几种方法可以拆分类的实现。除了修复臃肿的类设计之外,更好的方法是使用类别或类扩展。您可以在The Objective-C Programming Language 中阅读所有关于类别和扩展的信息。请注意,链接器在创建可执行文件时会将类别和扩展名合并到类中,因此在您自己的类上使用类别或扩展名不会有运行时损失。

The worse way is to use the C preprocessor's #includedirective to paste multiple files together. You can just take some methods out of the implementation file and stick them in new “fragment” file, then #includethe fragment file in the implementation file. Doing this will make it harder to understand your source code.I would notrecommend doing this, but here's an example anyway:

更糟糕的方法是使用 C 预处理器的#include指令将多个文件粘贴在一起。您可以从实现文件中取出一些方法并将它们粘贴到新的“片段”文件中,然后#include将片段文件粘贴到实现文件中。 这样做会使您更难理解您的源代码。建议这样做,但这里有一个例子:

MyObject.m

我的对象

#import "MyObject.h"

@implementation MyObject

- (void)aMethod { ... }

#include "MyObject-moreMethods.m"

@end

MyObject-moreMethods.m

MyObject-moreMethods.m

// Note: do not include this target in the “Compile Sources” build phase of your target.
// And **NO** @implementation statement here!

- (void)methodTwo { ... }

- (void)methodThree { ... }

回答by software evolved

[EDIT/UPDATE -- I have abandoned the approach described below in favor of using categories, as mentioned in some of the other answers. My typical situation is that as a view has control components added, the View Controller file becomes unwieldy as code is added to accommodate the various delegate and data source methods for the controls. Now I add in code stubs in the view controller file, then implement them for real in a class category. For instance, I might have an AlbumViewController screen that has a search bar and a collection view, so I create categories AlbumViewController+SearchBar and AlbumViewController+CollectionView. This allows the View Controller class to stay at a reasonable size, without incurring any of the drawbacks I listed below for included files. The only downside is that any instance variables, ie properties, must be declared publicly for a category to access them.]

[编辑/更新——我已经放弃了下面描述的方法,转而使用类别,正如其他一些答案中提到的那样。我的典型情况是,当视图添加了控件组件时,视图控制器文件变得笨拙,因为添加了代码以适应控件的各种委托和数据源方法。现在我在视图控制器文件中添加代码存根,然后在类类别中实现它们。例如,我可能有一个 AlbumViewController 屏幕,它有一个搜索栏和一个集合视图,所以我创建了类别 AlbumViewController+SearchBar 和 AlbumViewController+CollectionView。这允许 View Controller 类保持合理的大小,而不会产生我在下面列出的包含文件的任何缺点。唯一的缺点是任何实例变量,即属性,

I also want to split my files up, but think categories are not the correct solution in some cases. For example, as nibs grow to include multiple objects (such as tables, buttons, nav bars, tabs, etc) the need for placing all the supporting methods in the viewcontroller.m file can lead to a very large and unwieldy file.

我也想拆分我的文件,但认为类别在某些情况下不是正确的解决方案。例如,随着笔尖增长到包含多个对象(例如表格、按钮、导航栏、选项卡等),需要将所有支持方法放在 viewcontroller.m 文件中可能会导致文件非常大且笨拙。

For this discussion, I am going to refer to the original/standard .m file as the parent, and the subsidiary .m files as children.

在本次讨论中,我将原始/标准 .m 文件称为父文件,将附属 .m 文件称为子文件。

The goal is to have a single parent .h and .m, and multiple child .m files each of which can be edited independently, but compiled as if all the child .m files were in the parent .m file.

目标是拥有单个父 .h 和 .m,以及多个子 .m 文件,每个文件都可以独立编辑,但编译时就像所有子 .m 文件都在父 .m 文件中一样。

This would be useful if one wants the ability to, for instance, place all table related methods in a file, edit it, and then have it compile as if it were included in the viewcontroller.m implementation file. It seems this is possible, but requires a little effort, and has one (possibly serious) drawback.

例如,如果您希望能够将所有与表相关的方法放在一个文件中,编辑它,然后编译它,就好像它包含在 viewcontroller.m 实现文件中一样,这将非常有用。看起来这是可能的,但需要一点努力,并且有一个(可能是严重的)缺点。

The thing to keep in mind is that there are two distinct tools being used: the IDE (which provides intelligent source editing) and the compiler/make system which turns a project's source code into a runnable app.

要记住的是,有两个不同的工具被使用:IDE(提供智能源编辑)和编译器/make 系统,它将项目的源代码转换为可运行的应用程序。

To get the IDE to work as expected, the child files need to appear to be part of the implementation of the class. This can be accomplished by wrapping the @implementation and @end directives in conditional compilation macros. When editing a file on its own, the IDE considers the child files to be the body of the class, but the compiler doesn't.

为了让 IDE 按预期工作,子文件需要看起来是类实现的一部分。这可以通过在条件编译宏中包装@implementation 和@end 指令来实现。单独编辑文件时,IDE 将子文件视为类的主体,但编译器不会。

To get the compiler to not complain, you can't have the child files considered part of the target -- instead they get pulled in through the preprocessor #include directive. This can be accomplished by not adding them to the target when the file is created (or added to the project), or by removing them on the "Build Phases" -> "Compile Sources" pane.

为了让编译器不抱怨,您不能将子文件视为目标的一部分——而是通过预处理器 #include 指令将它们拉入。这可以通过在创建文件(或添加到项目)时不将它们添加到目标来实现,或者通过在“构建阶段”->“编译源”窗格中删除它们来实现。

You then #include the child .m files within the body of the parent .m files. The compiler loads them "in place" and compiles the source as wished for without complaints.

然后在父 .m 文件的正文中 #include 子 .m 文件。编译器“就地”加载它们,并根据需要编译源代码,没有任何抱怨。

The drawback of this approach (so far) is that the debugger does not recognize the child methods, and will not break on breakpoints put on them. For that reason I suggest that this approach only be used either after the code is thoroughly tested, or for code chunks that are relatively trivial and well-known, such as table delegate and data source methods.

这种方法的缺点(到目前为止)是调试器无法识别子方法,并且不会在放置在它们上的断点处中断。出于这个原因,我建议这种方法只能在代码经过彻底测试后使用,或者用于相对简单和众所周知的代码块,例如表委托和数据源方法。

Here are the .h and .m files for a project with a table and a text field in a nib, with the supporting delegate methods defined in child .m files. In the nib, the interface objects are wired up normally, and have the delegates set to the file owner.

下面是一个项目的 .h 和 .m 文件,在 nib 中有一个表和一个文本字段,支持的委托方法定义在子 .m 文件中。在 nib 中,接口对象正常连接,并将委托设置为文件所有者。

File (parent) "MyViewController.h":

文件(父)“MyViewController.h”:

#import <UIKit/UIKit.h>

@interface MyViewController : UIViewController

@property (retain, nonatomic) IBOutlet UITableView *myTable;
@property (retain, nonatomic) IBOutlet UITextField *myTextField;

@end

File (parent) MyViewController.m:

文件(父)MyViewController.m:

#import "MyViewController.h"

#define VIEW_CONTROLLER_MAIN_BODY   1

@interface MyViewController ()

@end

@implementation MyViewController

#include "MyViewController_TableMethods.m"
#include "MyViewController_TextFieldMethods.m"

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)dealloc {
    [_myTable release];
    [_myTextField release];
    [super dealloc];
}

File (child) MyViewController_TableMethods.m:

文件(子)MyViewController_TableMethods.m:

#import <UIKit/UIKit.h>
#import "MyViewController.h"

#ifndef VIEW_CONTROLLER_MAIN_BODY
@implementation ViewController
#endif

#pragma mark -
#pragma mark Table View Common Methods

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
{
    return 5;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
    static NSString *myIdentifier =    @"myCellIdentifier";
    static UITableViewCellStyle myStyle = UITableViewCellStyleSubtitle;

    UITableViewCell *cell = [self.myTable dequeueReusableCellWithIdentifier:myIdentifier];
    if (cell == nil)
    {
        cell = [[[UITableViewCell alloc] initWithStyle:myStyle reuseIdentifier:myIdentifier] autorelease];
    }


    cell.textLabel.text = @"Title";
    cell.detailTextLabel.text =  @"Details";
    cell.accessoryType = UITableViewCellAccessoryNone; 

    return cell;
}

#ifndef VIEW_CONTROLLER_MAIN_BODY
@end
#endif

File (child) MyViewController_TextFieldMethods.m:

文件(子)MyViewController_TextFieldMethods.m:

#import <UIKit/UIKit.h>
#import "MyViewController.h"

#ifndef VIEW_CONTROLLER_MAIN_BODY
@implementation MyViewController
#endif


- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
    self.myTextField.text = @"Woo hoo!";

    return YES;
}

#ifndef VIEW_CONTROLLER_MAIN_BODY
@end
#endif

回答by justin

This is a good indication that your class is just too large.

这是一个很好的迹象,表明您的班级太大了。

One approach: Use categories. Declarations can often stay in the header. Then your implementations may be divided. Just make sure to specify the category you are implementing, so the compiler may match it with its declaration, and inform you when you miss a definition.

一种方法:使用类别。声明通常可以留在标题中。那么你的实现可能会被划分。只需确保指定您正在实现的类别,这样编译器就可以将其与其声明相匹配,并在您错过定义时通知您。

回答by Kraming

A good way to break-down your big class is group functionality in Categories(like Apple does in UIViewController). For a big class, I generally group methods and properties related to their repective functionality and then In base header file, I split

一个好办法击穿你的大类组的功能类别(如苹果确实在UIViewController中)。对于一个大类,我通常将与其各自功能相关的方法和属性分组,然后在基本头文件中,我拆分

@interface SomeClass : NSObject
@property (strong, nonatomic) BaseProperty *sp;
- (void)someMethodForBase;
@end

@interface SomeClass (FunctionalityOne)
@property (strong, nonatomic) FuncOne *fpOne;
- (void)someMethodForFunctionalityOne;
@end

@interface SomeClass (FunctionalityTwo)
@property (strong, nonatomic) FuncTwo *fpTwo;
- (void)someMethodForFunctionalityTwo;
@end

Because you can't add property in category (You can't add new iVar and property don't synthesis in category) so you declare it in implementation of base Extension again.

因为你不能在类别中添加属性(你不能在类别中添加新的 iVar 和属性不要合成)所以你再次在 base Extension 的实现中声明它。

@interface SomeClass()
@property (strong, nonatomic) FuncOne *fpOne;
@property (strong, nonatomic) FuncTwo *fpTwo;
@end

@implementation SomeClass
//base class implementation
- (void)someMethodForBase {
}
@end

Implementing respective functionality in SomeClass+FunctionalityOne.m

在 SomeClass+FunctionalityOne.m 中实现各自的功能

@implementation SomeClass (FunctionalityOne)
@dynamic fpOne;
//Functionality one implementation
- (void)someMethodForFunctionalityOne {
}
@end

Implementing respective functionality in SomeClass+FunctionalityTwo.m

在 SomeClass+FunctionalityTwo.m 中实现各自的功能

@implementation SomeClass (FunctionalityTwo)
@dynamic fpTwo;
//Functionality two implementation
- (void)someMethodForFunctionalityTwo {
}
@end

This way I cleanly organise my big class implementation into small classes and all class functionalities information grouped in single base header for read and import.

通过这种方式,我将我的大类实现干净地组织成小类,并将所有类功能信息分组在单个基头中以供读取和导入。

回答by iOS Coder

its better to use Categories in iOS keep the code clean .

最好在 iOS 中使用 Categories 保持代码干净。