在实现中创建方法而不在头文件中定义

时间:2021-12-26 15:07:00

How can I create a method in the @implementation of a class without defining it in the @interface?

如何在类的@implementation中创建一个方法而不在@interface中定义它?

For example, I have a constructor that does some initialisation and then reads data from a file. I want to factor out the file-reading code into a separate method that I then call from within the constructor. I don't want to define this method in the header because it's private only to this @implementation context.

例如,我有一个构造函数,它进行一些初始化,然后从文件中读取数据。我想将文件读取代码分解为一个单独的方法,然后我在构造函数中调用它。我不想在标题中定义此方法,因为它仅对此@implementation上下文是私有的。

Is this possible?

这可能吗?

Here's my example. I have a little program that read's a Todo task-list from a file.

这是我的例子。我有一个小程序,它从文件中读取了Todo任务列表。

Here is the @interface:

这是@interface:

@interface TDTaskList : NSObject {
  NSString* name; // The name of this list.
  NSMutableArray* tasks;  // The set of tasks in this list.
}

-(id)initListOfName:(NSString*)aName;
-(NSArray*)loadListWithName:(NSString*)aName;

@end

And here is part of the @implementation:

这是@implementation的一部分:

-(id)initListOfName:(NSString*)aName {
  if (self = [super init]) {
    name = aName;

    NSArray* aTasks = [self loadListWithName:aName];
    tasks = [NSMutableArray arrayWithArray:aTasks];
  }

  return self;
}

-(NSArray*)loadListWithName:(NSString*)aName {
  // TODO This is a STUB till i figure out how to read/write from a file ...

  TDTask* task1 = [[TDTask alloc] initWithLabel:@"Get the Milk."];
  TDTask* task2 = [[TDTask alloc] initWithLabel:@"Do some homework."];

  return [NSArray arrayWithObjects:task1, task2, nil];
}

What I want to do is to not have to define the following in the interface:

我想要做的是不必在界面中定义以下内容:

-(NSArray*)loadListWithName:(NSString*)aName;

4 个解决方案

#1


If you place the implementation of a method before any code that calls it you do not need to define it in the header.

如果在任何调用它的代码之前放置方法的实现,则不需要在标头中定义它。

So in this case put loadListWithName: in front of initListOfName: in the @implementation block and it will be good.

所以在这种情况下,在@implementation块中将loadListWithName:放在initListOfName:之前,它会很好。

Note: Just because it is not defined in the header does not mean the method cannot be called by code outside of the object. Objective-C does not have private methods.

注意:仅仅因为它未在标头中定义并不意味着该方法不能被对象外部的代码调用。 Objective-C没有私有方法。

#2


As Andy hinted in the comments, you can use Extensions (which look like a category without a name). The difference is that you must implement the methods declared in an extension whereas the compiler doesn't verify that you implement methods declared in a category.

正如Andy在评论中暗示的那样,你可以使用Extensions(看起来像一个没有名字的类别)。不同之处在于您必须实现扩展中声明的方法,而编译器不会验证您是否实现了类别中声明的方法。

.h:

@interface MyObject : NSObject
{
    NSNumber *number;
}
- (NSNumber *)number;
@end

.m:

@interface MyObject ()
- (void)setNumber:(NSNumber *)newNumber;
@end

@implementation MyObject

- (NSNumber *)number
{
    return number;
}
- (void)setNumber:(NSNumber *)newNumber
{
    number = newNumber;
}
@end

#3


You could use categories:

你可以使用类别:

// In TDTaskList.m
@interface TDTaskList(TDTaskListPrivate)
-(id)initListOfName:(NSString*)aName;
-(NSArray*)loadListWithName:(NSString*)aName;
@end

@implementation TDTaskList(TDTaskListPrivate)

// implementation of initListOfName and loadListWithName ...

@end

#4


You have two reasonable options. Both were basically described already but IMHO were a bit unclear or even plain wrong.

你有两个合理的选择。两者基本上已经描述过,但恕我直言有点不清楚甚至是完全错误。

Categories are not one of them as they are AFAIK meant for the entirely different purpose of breaking implementations into multiple source files.

类别不是其中之一,因为它们是AFAIK意味着将实现分解为多个源文件的完全不同的目的。

  • Do as Nathan described above. Though he is wrong with his last assumption (private methods).
  • 像Nathan上面描述的那样。虽然他最后的假设是错误的(私人方法)。

  • Use a private method extension definition to allow forward referencing as follows:

    1. remove the definition of loadListWithName from your header entirely
    2. 完全从标头中删除loadListWithName的定义

    3. add the following into the source (.m) before the @implementation block
    4. 在@implementation块之前将以下内容添加到源(.m)中

    @interface TDTaskList (PrivateMethods)
    -(NSArray*)loadListWithName:(NSString*)aName;
    @end
    
    @implementation ...
    

  • 使用私有方法扩展定义允许转发引用,如下所示:从头部删除loadListWithName的定义,在@implementation块之前将以下内容完全添加到源(.m)中 @interface TDTaskList(PrivateMethods) - (NSArray的*)loadListWithName:(的NSString *)aName; @结束 @implementation ...

    #1


    If you place the implementation of a method before any code that calls it you do not need to define it in the header.

    如果在任何调用它的代码之前放置方法的实现,则不需要在标头中定义它。

    So in this case put loadListWithName: in front of initListOfName: in the @implementation block and it will be good.

    所以在这种情况下,在@implementation块中将loadListWithName:放在initListOfName:之前,它会很好。

    Note: Just because it is not defined in the header does not mean the method cannot be called by code outside of the object. Objective-C does not have private methods.

    注意:仅仅因为它未在标头中定义并不意味着该方法不能被对象外部的代码调用。 Objective-C没有私有方法。

    #2


    As Andy hinted in the comments, you can use Extensions (which look like a category without a name). The difference is that you must implement the methods declared in an extension whereas the compiler doesn't verify that you implement methods declared in a category.

    正如Andy在评论中暗示的那样,你可以使用Extensions(看起来像一个没有名字的类别)。不同之处在于您必须实现扩展中声明的方法,而编译器不会验证您是否实现了类别中声明的方法。

    .h:

    @interface MyObject : NSObject
    {
        NSNumber *number;
    }
    - (NSNumber *)number;
    @end
    

    .m:

    @interface MyObject ()
    - (void)setNumber:(NSNumber *)newNumber;
    @end
    
    @implementation MyObject
    
    - (NSNumber *)number
    {
        return number;
    }
    - (void)setNumber:(NSNumber *)newNumber
    {
        number = newNumber;
    }
    @end
    

    #3


    You could use categories:

    你可以使用类别:

    // In TDTaskList.m
    @interface TDTaskList(TDTaskListPrivate)
    -(id)initListOfName:(NSString*)aName;
    -(NSArray*)loadListWithName:(NSString*)aName;
    @end
    
    @implementation TDTaskList(TDTaskListPrivate)
    
    // implementation of initListOfName and loadListWithName ...
    
    @end
    

    #4


    You have two reasonable options. Both were basically described already but IMHO were a bit unclear or even plain wrong.

    你有两个合理的选择。两者基本上已经描述过,但恕我直言有点不清楚甚至是完全错误。

    Categories are not one of them as they are AFAIK meant for the entirely different purpose of breaking implementations into multiple source files.

    类别不是其中之一,因为它们是AFAIK意味着将实现分解为多个源文件的完全不同的目的。

  • Do as Nathan described above. Though he is wrong with his last assumption (private methods).
  • 像Nathan上面描述的那样。虽然他最后的假设是错误的(私人方法)。

  • Use a private method extension definition to allow forward referencing as follows:

    1. remove the definition of loadListWithName from your header entirely
    2. 完全从标头中删除loadListWithName的定义

    3. add the following into the source (.m) before the @implementation block
    4. 在@implementation块之前将以下内容添加到源(.m)中

    @interface TDTaskList (PrivateMethods)
    -(NSArray*)loadListWithName:(NSString*)aName;
    @end
    
    @implementation ...
    

  • 使用私有方法扩展定义允许转发引用,如下所示:从头部删除loadListWithName的定义,在@implementation块之前将以下内容完全添加到源(.m)中 @interface TDTaskList(PrivateMethods) - (NSArray的*)loadListWithName:(的NSString *)aName; @结束 @implementation ...