3

我目前正在为 API 制作一个 Objective-C 库。为了轻松管理数据,我创建了一些充当模型的类。

例如,我有一个Account类,其中包含有关一个特定帐户的所有数据。我想让这个类的初始化变得容易,我想到了这样的事情:

@interface Account : NSObject

@property (nonatomic, readonly) NSUInteger accountID;
@property (nonatomic, readonly) NSString *username;

// Other properties...

+ (instancetype)accountWithUsername:(NSString *)username success:(void (^)(Account *))success failure:(void (^)(NSError *))failure;
- (instancetype)initWithUsername:(NSString *)username success:(void (^)(Account *))success failure:(void (^)(NSError *))failure;

@end

 

@implementation Account

+ (instancetype)accountWithUsername:(NSString *)username success:(void (^)(Account *))success failure:(void (^)(NSError *))failure
{
    return [[JPImgurAccount alloc] initWithUsername:username success:success failure:failure];
}

- (instancetype)initWithUsername:(NSString *)username success:(void (^)(Account *))success failure:(void (^)(NSError *))failure
{
    self = [super init];

    // Launch asynchronous requests, the callback will be called when it's finished

    return self; // Returning an empty object until the asynchronous request is finished
}

@end

但是,通过该方法返回一个空对象init让我有点困扰,我问自己这是否是一个好主意,但我不知道为什么它可能会有风险。

所以我问你:我可以使用这个结构吗?如果不是,为什么?我应该以经典方式使用与init方法耦合的单个loadWithUsername:(NSString *)username success:(void (^)(JPImgurAccount *))success failure:(void (^)(NSError *))failure方法吗?

谢谢。

4

4 回答 4

5

我不认为你的方法是好的做法。作为 API 的用户,当我看到一个以“init”开头的方法时,我希望返回的对象可以立即使用。看起来您需要使用工厂设计模式。使用此方法创建一个 AccountFactory 类:

+ (void)createAccountWithUsername:(NSString*)username success:(void (^)(Account *))success failure:(void (^)(NSError *))failure;

请注意,它返回 void,因此用户了解该对象仅在请求成功完成后才可用。此外,用户了解他不应该直接创建 Account 实例。这就是我会使用的方法。

于 2013-07-13T20:45:28.550 回答
3

但是,通过 init 方法返回一个空对象让我有点困扰,我问自己这是否是一个好主意,但我不知道为什么它可能会有风险。

你是对的。这是个坏主意。很多人会立即使用结果而不了解它的初始化是异步发生的。另一个问题是,如果您返回一个对象,他们会认为它是有效的。因此,如果帐户最终无法初始化,您的客户可能不会检查它是否已正确初始化。这也使得客户端代码的执行变得不必要地奇怪。

Apple 框架中使用的惯用语通常是Request。所以有一些使用这种设计的类,你可以寻找指导,以便 API 更熟悉(它们的名称包含“请求”)。有些人会使用委托,但块通常更可取——尤其是对于像这样简单的事情。

使用这种方法,您可以使客户端可以(合理地)访问 an 实例的唯一方法Account是通过AccountRequestAPI。

于 2013-07-13T21:04:12.470 回答
2

我会使用一个类方法,类似于你的(有两个块,一个代表成功,一个代表失败)但省略了返回类型。这种语法符合普通的 Objective-C 风格。例如,您可以:

+ (void)loadAccountWithUsername:(NSString *)username success:(void (^)(Account *))success failure:(void (^)(NSError *))failure

在空对象上使用 'void' 是非常受欢迎的,因为返回一个没有任何用途的对象是多余且毫无意义的。为了向用户重申不能以“传统”方式(通过[[Account alloc] init])初始化 Account 类,您可以init通过类方法抛出一个描述所需初始化流程的异常。

于 2013-07-13T20:46:38.410 回答
0

您可以使用这种结构,但大多数人使用Key Value Observing来通知感兴趣的类对属性的更改。您仍然会在初始化期间发出异步请求。但是,您只需在请求完成时发出更改属性的通知,而不是稍后在回调中返回该类。

于 2013-07-13T20:50:49.757 回答