ios - 如何将局部变量更改为实例变量?

标签 ios objective-c cocoa

所以我对此完全陌生。 我正在学习本地的天气教程

http://www.icodeblog.com/2010/09/03/adding-local-weather-conditions-to-your-app-part-12-implementing-corelocation/

它没有正常工作。当我点击“运行”时,会弹出一个窗口,提示您是否允许此应用访问位置管理器。但是消息在我有机会点击它之前就消失了,然后应用程序什么也没做。

下面是我的代码...经过研究我发现了这个信息

虽然很难追踪,但解决方案非常简单。

通过反复试验,我发现当您第一次尝试访问应用程序中的任何位置服务时会弹出位置访问对话框,但如果 CLLocationManager 对象在用户响应对话框之前被释放。

我在 viewDidLoad 方法中创建了一个 CLLocationManager 实例。由于这是该方法的本地实例,该实例在方法执行完毕后由 ARC 释放。实例一发布,对话框就消失了。解决方案相当简单。将 CLLocationManager 实例从方法级变量更改为类级实例变量。现在,CLLocationManager 实例只会在类卸载后释放。

这可能是答案,但我不知道如何从方法级别更改为类级别变量。

有人可以协助将其更改为类级别变量吗?

这是我的代码

#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>

@protocol LocationGetterDelegate <NSObject>
@required
- (void) newPhysicalLocation:(CLLocation *)location;
@end

@interface LocationGetter : NSObject
<CLLocationManagerDelegate>{
    CLLocationManager *locationManager;
    id delegate;
}

-(void)startUpdates;

@property (nonatomic, retain) CLLocationManager *locationManager;
@property (nonatomic, retain) id delegate;

@end


    #import "LocationGetter.h"
    #import <CoreLocation/CoreLocation.h>

@implementation LocationGetter

@synthesize locationManager,delegate;
BOOL didUpdate = NO;

- (void) startUpdates{
    NSLog(@"Starting Location Updates");

    if (locationManager == nil)
        locationManager = [[CLLocationManager alloc]init];
    locationManager.delegate = self;

    locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
    [locationManager startUpdatingLocation];
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Your location could not be determined." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
    [alert show];
}

// Delegate method from the CLLocationManagerDelegate protocol.
- (void)locationManager:(CLLocationManager *)manage didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
    if (didUpdate)
        return;

    didUpdate = YES;
    // Disable future updates to save power.
    [locationManager stopUpdatingLocation];

    // let our delegate know we're done
    [delegate newPhysicalLocation:newLocation];
}

@end



    #import <UIKit/UIKit.h>
    #import "LocationGetter.h"

@class ViewController;

@interface AppDelegate : UIResponder
    <UIApplicationDelegate, LocationGetterDelegate>
{
    UIWindow *window;
    ViewController *viewController;
    CLLocation *lastKnownLocation;

}

@property (retain, nonatomic) UIWindow *window;

@property (retain, nonatomic) ViewController *viewController;

@property (nonatomic, retain) CLLocation *lastKnownLocation;

@end




    #import "AppDelegate.h"
    #import "ViewController.h"
    #import "LocationGetter.h"

@implementation AppDelegate

@synthesize lastKnownLocation;
@synthesize viewController;
@synthesize window;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
//    // Override point for customization after application launch.
//    self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
//    self.window.rootViewController = self.viewController;
//    [self.window makeKeyAndVisible];

    UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
    spinner.center = CGPointMake(self.viewController.view.frame.size.width / 2, self.viewController.view.frame.size.height / 2);
    [spinner startAnimating];

    [viewController.view addSubview:spinner];

    // get our physical location
    LocationGetter *locationGetter = [[LocationGetter alloc] init];
    locationGetter.delegate = self;
    [locationGetter startUpdates];

    // Add the view controller's view to the window and display.
    [window addSubview:viewController.view];
    [window makeKeyAndVisible];



    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application
{
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

- (void)newPhysicalLocation:(CLLocation *)location {

    // Store for later use
    self.lastKnownLocation = location;

    // Remove spinner from view
    for (UIView *v in [self.viewController.view subviews])
    {
        if ([v class] == [UIActivityIndicatorView class])
        {
            [v removeFromSuperview];
            break;
        }
    }

    // Alert user
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Location Found" message:[NSString stringWithFormat:@"Found physical location.  %f %f", self.lastKnownLocation.coordinate.latitude, self.lastKnownLocation.coordinate.longitude] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
    [alert show];
}


@end

最佳答案

您需要解决一些问题。首先,您的 locationManager 已经是一个实例变量。那里没有什么可以改变的。但是您声明了 locationManager 属性但从不使用它。摆脱属性(property)或实际使用它。如果您保留该属性,则它不需要公开,因为没有外部类在使用它。

此外,您的 delegate 属性定义不正确。

您遇到的真正问题是您的应用委托(delegate)实现。您创建了 LocationGetter 的本地实例,然后让它在方法结束时超出范围。您需要将 LocationGetter 实例变量添加到您的应用委托(delegate)。这将允许该实例比 didFinishLaunchingWithOptions: 方法存活的时间更长。

下面是我将如何更新代码(假设启用了 ARC):

位置 getter .h:

#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>

@protocol LocationGetterDelegate <NSObject>
@required
- (void) newPhysicalLocation:(CLLocation *)location;
@end

@interface LocationGetter : NSObject

-(void)startUpdates;

@property (nonatomic, weak) id<LocationGetterDelegate> delegate;

@end

LocationGetter.m:

#import "LocationGetter.h"
#import <CoreLocation/CoreLocation.h>

@interface LocationGetter () <CLLocationManagerDelegate>

@property (nonatomic, strong) CLLocationManager *locationManager;

@end

@implementation LocationGetter {
    BOOL didUpdate = NO;
}

- (void) startUpdates{
    NSLog(@"Starting Location Updates");

    if (self.locationManager == nil)
        self.locationManager = [[CLLocationManager alloc]init];
    self.locationManager.delegate = self;

    self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
    [self.locationManager startUpdatingLocation];
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Your location could not be determined." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
    [alert show];
}

// Delegate method from the CLLocationManagerDelegate protocol.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
    if (didUpdate)
        return;

    didUpdate = YES;
    // Disable future updates to save power.
    [manager stopUpdatingLocation];

    // let our delegate know we're done
    [self.delegate newPhysicalLocation:newLocation];
}

@end

AppDelegate.h:

#import <UIKit/UIKit.h>

@class ViewController;

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) ViewController *viewController;
@property (nonatomic, strong) CLLocation *lastKnownLocation;

@end

AppDelegate.m:

#import "AppDelegate.h"
#import "ViewController.h"
#import "LocationGetter.h"

@interface AppDelegate () <LocationGetterDelegate>
@property (nonatomic, strong) LocationGetter *locationGetter;
@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
//    // Override point for customization after application launch.
//    self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
//    self.window.rootViewController = self.viewController;
//    [self.window makeKeyAndVisible];

    UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
    spinner.center = CGPointMake(self.viewController.view.frame.size.width / 2, self.viewController.view.frame.size.height / 2);
    [spinner startAnimating];

    [viewController.view addSubview:spinner];

    // get our physical location
    self.locationGetter = [[LocationGetter alloc] init];
    self.locationGetter.delegate = self;
    [self.locationGetter startUpdates];

    // Add the view controller's view to the window and display.
    [window addSubview:viewController.view];
    [window makeKeyAndVisible];

    return YES;
}

关于ios - 如何将局部变量更改为实例变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15079419/

相关文章:

iphone - ID : Library not found for -lMBProgressHUD

objective-c - 由于内存警告而卸载 View Controller 时如何保留状态?

iphone - 如何在不使我的应用程序崩溃的情况下发布此 NSXMLParser?

objective-c - 当考虑 Objective-C 中的 "Library"时,我必须想象什么?

javascript - Cordova AppRate 插件 "Rate it now"按钮在 iOS 上不起作用

ios - 如果响应通知调用 view.window.center 为 0,0,否则为 160,284

ios - 如何在设备应用商店中预览我的应用名称?

ios - 无需程序员干预的 Storyboard UI 更改

objective-c - iOS 非导航栏基于导航和 View 交换

macos - 无法访问用户默认值