0

だから私はこれに完全に慣れていません。私は地元の天気のチュートリアルに従っています

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

正常に機能していません。RUN を押すと、このアプリにロケーション マネージャーへのアクセスを許可するかどうかを示すウィンドウがポップアップ表示されます。しかし、メッセージを打つ前にメッセージが消えてしまい、アプリは何もしません。

以下は私のコードです...調査すると、この情報が見つかりました

追跡するのは困難ですが、これに対する解決策は非常に簡単です。

多くの試行錯誤の結果、アプリ内の位置情報サービスに初めてアクセスしようとすると、位置情報アクセス ダイアログがポップアップしますが、CLLocationManagerオブジェクトが以前に解放されると、ダイアログは (ユーザーの操作なしで) 自動的に消えることがわかりました。ユーザーがダイアログに応答します。

CLLocationManagerメソッドでインスタンスを作成していましたviewDidLoad。これはメソッドのローカル インスタンスであるため、メソッドの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
4

2 に答える 2

2

修正する必要があることがいくつかあります。まず、あなたlocationManagerはすでにインスタンス変数です。そこに変更するものは何もありません。しかし、あなたは財産を宣言しlocationManagerますが、決してそれを使用しません。プロパティを削除するか、実際に使用します。プロパティを保持する場合、外部のクラスがそれを使用していないため、パブリックである必要はありません。

また、delegateプロパティが正しく定義されていません。

発生している実際の問題は、アプリデリゲートの実装が原因です。のローカルインスタンスを作成しLocationGetter、メソッドの最後でスコープ外に移動します。LocationGetterアプリデリゲートにインスタンス変数を追加する必要があります。これにより、インスタンスはdidFinishLaunchingWithOptions:メソッドだけでなく、より長く存続できるようになります。

コードを更新する方法は次のとおりです(ARCが有効になっていると仮定)。

LocationGetter.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;
}
于 2013-02-26T01:41:28.093 に答える
1

クラス変数ではなくインスタンス変数に変更することを意味していると思います(Objective-Cにはそのような概念はありません)。まあ、あなたはすでにそれをしました。ここに住んでいるもの:

@interface Foo : SuperFoo
{
    //...
}

またはここ:

@implementation Foo
{
    //...
}

インスタンス変数です。

于 2013-02-26T01:24:14.407 に答える