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」で始まるメソッドを見ると、返されたオブジェクトがすぐに使用できる状態になっていることを期待します。Factory デザイン パターンを使用する必要があるようです。このメソッドで AccountFactory クラスを作成します。

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

void を返すことに注意してください。ユーザーは、リクエストが正常に終了した場合にのみオブジェクトを使用できることを理解できます。また、ユーザーは Account のインスタンスを直接作成する必要がないことを理解しています。それが私が使用するアプローチです。

于 2013-07-13T20:45:28.550 に答える
3

しかし、init メソッドを介して空のオブジェクトを返すのは少し気になり、本当に良いアイデアなのか自問自答しましたが、なぜ危険なのかわかりません。

あなたが正しい。それは悪い考えです。多くの人は、初期化が非同期で行われていることを理解せずに、結果をすぐに使用するだけです。もう1つの問題は、オブジェクトを返すと、それが有効なものであると想定されることです。そのため、最終的にアカウントを初期化できない場合、アカウントが正しく初期化されたかどうかを確認しないクライアントがいる可能性があります。これにより、クライアントのコードの実行が不必要に奇妙になります。

Apple のフレームワークで使用されるイディオムは通常、Requestです。そのため、この設計を使用するいくつかのクラスがあり、ガイダンスとして参照できるため、API がより親しみやすくなっています (それらの名前には「Request」が含まれています)。委任を使用するものもありますが、一般的にはブロックが推奨されます。特に、このような単純なものの場合は特にそうです。

このアプローチを使用すると、クライアントが (合理的に) のインスタンスにアクセスできる唯一の方法がAPIAccountを介するようにすることができます。AccountRequest

于 2013-07-13T21:04:12.470 に答える
2

私はあなたと同様のクラスメソッドを使用します(成功用と失敗用の2つのブロックがあります)が、戻り値の型を省略しています。この構文は、通常の Objective-C スタイルに適合します。たとえば、次のようにすることができます。

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

何の目的も果たさないオブジェクトを返すことは冗長で無意味であるため、空のオブジェクトに対して 'void' を使用することを強くお勧めします。Account クラスを「従来の」方法 ( 経由[[Account alloc] init]) で初期化できないことをユーザーに再確認するにはinit、必要な初期化フローがクラス メソッドによるものであることを説明する例外をスローすることができます。

于 2013-07-13T20:46:38.410 に答える
0

この構造を使用することもできますが、ほとんどの人はKey Value Observingを使用して、関心のあるクラスにプロパティの変更を通知します。初期化中に非同期リクエストを発行します。ただし、後でコールバックでクラスを返す代わりに、リクエストの完了時に変更されたプロパティの通知を発行するだけです。

于 2013-07-13T20:50:49.757 に答える