【问题标题】:method not called from app delegate in ios未从 ios 中的应用程序委托调用方法
【发布时间】:2013-11-02 19:45:14
【问题描述】:

我想从应用程序的其他地方调用一个方法来获取在应用程序委托中获取的用户位置。从另一个视图控制器调用CLLocation *getCurLoc = [AppDelegate getCurrentLocation]; 时,没有返回任何内容。

应用代理是,

@synthesize locationManager;

CLLocation *location;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

    locationManager = [[CLLocationManager alloc]init];
    locationManager.delegate = self;
    locationManager.desiredAccuracy=kCLLocationAccuracyKilometer;
    [locationManager startUpdatingLocation];

    return YES;
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{

    [locations lastObject];
    [manager stopUpdatingLocation];

    CLLocation *location =  [locations lastObject];
}

+(CLLocation *)getCurrentLocation{
    return location;
}

将其更改为带有“-”的实例方法不起作用。是否应该将“位置”作为实例?应该将委托制作成一个实例,还是有更好的方法从其他地方访问它?

【问题讨论】:

  • 你的CLLocation *location 应该被实现为一个ivar 或作为一些保存数据(模型)的类的属性。

标签: ios objective-c delegates cllocationmanager


【解决方案1】:

didUpdateLocations 中,您定义并设置了一个本地 变量location,而不是文件顶部定义的全局 变量location。换行

CLLocation *location =  [locations lastObject];

location =  [locations lastObject];

可以解决问题。但更好的解决方案是使用 AppDelegate 类中的属性。 您可以在类扩展中定义它:

@interface AppDelegate ()
@property(strong, nonatomic) CLLocation *location;
@end

然后你在实例方法中访问它

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{

    [locations lastObject];
    [manager stopUpdatingLocation];
    self.location =  [locations lastObject];
}

在一个类方法

+(CLLocation *)getCurrentLocation{
    // Get the instance:
    AppDelegate *app = [[UIApplication sharedApplication] delegate];

    return app.location;
}

更新:如果 AppDelegate 被声明为符合某些协议(在 公共接口或类扩展中),例如:

@interface AppDelegate () <CLLocationManagerDelegate>
@property(strong, nonatomic) CLLocation *location;
@end

那么上面的代码会产生一个警告

initializing 'AppDelegate *__strong' with an expression of incompatible type 'id<UIApplicationDelegate>'

并且需要显式转换:

+(CLLocation *)getCurrentLocation{
    // Get the instance:
    AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];

    return app.location;
}

【讨论】:

  • 当使用'AppDelegate app = [[UIApplication sharedApplication] delegate];'我收到警告 __strong' 的表达式与类型 id 不兼容。我发现如果我将此答案与 gimenetes 的答案结合起来,我可以使用 '+ (AppDelegate *)sharedDelegate { return (AppDelegate)[UIApplication sharedApplication].delegate; }'
  • @BobGreen:你是对的。当我对此进行测试并写下答案时,我没有收到警告,但我弄清楚了为什么在你的情况下需要强制转换,并更新了答案。
【解决方案2】:

Martin's answer 是以与您的方法一致的方式解决此问题的一种有效的快速而简单的方法 - 将位置存储在 appDelegate 中。

如果您想更进一步,您可能需要考虑实现一个保存数据的特殊对象 - 数据模型。在应用程序委托中存储数据被认为是一种不好的做法 - 这不是它的用途(尽管它在示例或小型应用程序中工作得很好)。

你可以这样做:

DataModel.h

#import <Foundation/Foundation.h>

@interface DataModel : NSObject

@property (strong) CLLocation *location;

+ (DataModel *)sharedModel;

@end

DataModel.m

#import "DataModel.h"

@class CLLocation;

@implementation DataModel

- (id) init
{
    self = [super init];
    if (self)
    {
        _location = nil;
    }
    return self;
}

+ (DataModel *)sharedModel
{
    static DataModel *_sharedModel = nil;
    static dispatch_once_t onceSecurePredicate;
    dispatch_once(&onceSecurePredicate,^
                  {
                      _sharedModel = [[self alloc] init];
                  });

    return _sharedModel;
}

@end

然后,您需要在任何需要的地方#import "DataModel.h"。您可以将 didUpdateLocations: 更改为:

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    [locations lastObject];
    [manager stopUpdatingLocation];

    [DataModel sharedInstance].location = [locations lastObject];
}

您可以从代码中的任何位置通过[DataModel sharedInstance].location 获取此位置。

编辑:

对于一个非常简单的应用程序,这种方法可能看起来有点矫枉过正。但是,一旦您的应用发展壮大,使用它肯定会有所回报。

这种类/对象/单例用于保存您的应用所需的所有数据(固定的和临时的)。所以所有的数据源都可以很好地利用它。简而言之:它使您能够轻松遵循模型-视图-控制器指南。

您当然可以使用另一个类/对象/单例来保存临时数据 - 这取决于您的数据结构的复杂性。

您不必专门初始化这种对象。它在您第一次引用它时被初始化。这就是为什么dispatch_once 存在的原因。它确保只有一个共享对象的实例存在:https://stackoverflow.com/a/9119089/653513

并且[DataModel sharedInstance] 的单个实例将保留在那里,直到您的应用程序终止。

例如,Apple 对[NSUserDefaults standardDefaults], [UIApplication sharedApplicaton] 使用了类似的方法。

我倾向于将#import "DataModel.h" 放入我的项目Prefix.pch,这样我就不必每次使用它时都导入它(它在所有应用程序中都使用)。

优点: - 整个应用程序均可访问数据 - 代码可重用性 - MVC结构 - 代码更具可读性

缺点: - 我真的找不到。除了dispatch_once(&amp;onceSecurePredicate,^... 可能会在前几秒内混淆。

【讨论】:

  • 我认为这是要走的路。我是否也可以通过添加更多属性让这个类存储来自其他类的数据,并使其成为存储一些临时数据的中心位置?另外我不确定调度或异步在做什么。你能解释更多吗?使用这种方法的优缺点是什么?
  • 实际上是的:像这样的类用于保存应用程序所需的所有数据。它使您能够真正以模型-视图-控制器的方式工作。我将在答案中添加更多解释。
【解决方案3】:

您可以使用[UIApplication sharedApplication].delegate 从应用程序中的任何位置访问AppDelegate,因此您可以这样做:

CLLocation *location = [(YourAppDelegateClassName*)[UIApplication sharedApplication].delegate getCurrentLocation];

方法getCurrentLocation 需要是实例方法(-(CLLocation *)getCurrentLocation)。您还需要在需要使用该方法的文件中导入#import "YourAppDelegateClassName.h"

为了避免每次我更喜欢在我的 AppDelegates 中实现静态方法时强制转换和访问 [UIApplication sharedApplication].delegate

+ (YourAppDelegateClassName*)sharedDelegate {
    return (YourAppDelegateClassName*)[UIApplication sharedApplication].delegate;
}

所以你可以使用任何这样的方法:

CLLocation *location = [[YourAppDelegateClassName sharedDelegate] getCurrentLocation];

【讨论】:

  • 对这个答案投反对票的人应该留下解释性评论。在我看来,当前所有三个答案都是该问题的可能解决方案。
  • 同意 Martin R 和 gimenete:为什么这个答案会被否决?我知道我们不应该为赔偿而投票,但它就这样......
  • 感谢 rokjarc 和 Martin 的支持
猜你喜欢
  • 2019-10-23
  • 1970-01-01
  • 2016-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多