3

私はiOS開発(私の最初のアプリ)にかなり慣れていないので、この問題に直面しました。

ユーザーがボタンをタッチすると、複数のViewControllerでユーザーの現在の場所を取得する必要があるiPhoneアプリがあります。冗長なコードを防ぐために (異なるビュー コントローラーで 、 などを複数回実装locationManager:didFailWithErrorするlocationManager:didUpdateToLocation:fromLocation)、次のようなカスタム クラスを作成することにしましたLocationManager

LocationManager.h

@interface LocationManager : NSObject <CLLocationManagerDelegate> {
@private
    CLLocationManager *CLLocationManagerInstance;
    id<LocationManagerAssigneeProtocol> assignee;
}

-(void) getUserLocationWithDelegate:(id) delegate;

LocationManager.m

@implementation LocationManager

-(id)init {
    self = [super init];
    if(self) {
        CLLocationManagerInstance = [[CLLocationManager alloc] init];
        CLLocationManagerInstance.desiredAccuracy = kCLLocationAccuracyBest;
        CLLocationManagerInstance.delegate = self;
    }
    return self;
}

-(void) getUserLocationWithDelegate:(id) delegate {
    if([CLLocationManager locationServicesEnabled]) {
        assignee = delegate;
        [CLLocationManagerInstance startUpdatingLocation];
    }
}

#pragma CLLocationManagerDelegate

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
...
}

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
    [CLLocationManagerInstance stopUpdatingLocation];
    [assignee didUpdateToLocation:newLocation];
}

ViewControllersが実装するLocationManagerAssigneeProtocolというプロトコルがあります

@protocol LocationManagerAssigneeProtocol <NSObject>

@required
-(void) didUpdateToLocation:(CLLocation *) location;

@end

そして、必要に応じてビューコントローラーで

- (IBAction)getMyLocation:(id)sender {

    [locationMgr getUserLocationWithDelegate:self];
}

LocationManagerこのコードは完全に機能しますが、Location Manager の呼び出しを開始したクラスの関数を呼び出せるようにすることで、ここでいくつかの設計パターンに違反していると感じています。一方、場所で動作するはずのすべてのビューコントローラーにCLLocationManagerDelegateを実装したくありません。

この問題に対するより良い解決策はありますか?

4

1 に答える 1

2

これについては@CarlVeazeyに同意します。デリゲートは、常に存在する 1 対 1 の関係に最適ですが、あなたのケースでは、いつでもロケーション イベントに応答するために複数の viewControllers が必要なようです。したがって、デリゲートとそれに関連するプロトコルに関連するものはすべて削除してください。

おそらく LocationManager クラスをシングルトンにして、更新用のメソッドを変更します。

+(LocationManager *)sharedInstance
{
    static LocationManager *_sharedInstance = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        _sharedInstance = [[self alloc] init];
    });

    return _sharedInstance;
}

-(void)getUserLocation
{
    if ([CLLocationManager locationServicesEnabled])
        [CLLocationManager startUpdatingLocation];
}

-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation 
{
    [CLLocationManagerInstance stopUpdatingLocation];
    [[NSNotificationCenter defaultCenter] postNotificationWithName:@"LocationManagerDidUpdateLocation" object:newLocation];
}

... 次に、このクラスを使用する必要がある viewController は次のようになります。

-(void)viewDidLoad
{
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserverForName:@"LocationManagerDidUpdateLocation" object:self queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
        CLLocation *location = note.object;
        ...
    }];
}

-(IBAction)getMyLocation:(id)sender {
    [[LocationManager sharedInstance] getUserLocation];
}

それが役に立ち、理にかなっていることを願っています。

于 2013-04-23T15:35:42.077 に答える