2009-01-19 32 views
22

मुझे पहले से ही पता है कि CLLocationManager का उपयोग कैसे करें, इसलिए मैं प्रतिनिधियों और सभी के साथ इसे कठिन तरीके से कर सकता हूं।आईफोन के वर्तमान स्थान को पाने का सबसे आसान तरीका क्या है?

लेकिन मुझे एक सुविधा विधि चाहिए जो केवल वर्तमान स्थान, एक बार, और जब तक परिणाम न हो जाए तब तक ब्लॉक हो।

+0

आप प्रश्न को स्पष्ट करना चाहिए: आप CLLocationManager उपयोग करने के लिए कैसे पता है - ऐसी "सुविधा विधि" को लागू करने में समस्या क्या है? – tcurdt

+10

मुझे लगता है कि समस्या यह है कि यह इतना आसान नहीं है। आम तौर पर यह पहले एक पुराना स्थान देता है, उसके बाद एक जंगली रूप से निर्विवाद व्यक्ति होता है, जिसके बाद प्रगतिशील बेहतर होते हैं, आप किस बिंदु पर निर्णय लेते हैं कि आप चाहते हैं कि आप चाहते हैं? यह वास्तव में आप पर निर्भर है। – rustyshelf

+0

अच्छा बिंदु, जंगली! –

उत्तर

4

कोई "सुविधा विधियां" नहीं हैं जबतक कि आप उन्हें स्वयं कोड नहीं करते हैं, लेकिन आपको अभी भी "सुविधाजनक" बनाने के लिए उपयोग किए जाने वाले कस्टम कोड में प्रतिनिधि विधियों को लागू करने की आवश्यकता होगी।

प्रतिनिधि पैटर्न एक कारण के लिए है, और प्रतिनिधि प्रतिनिधि-सी का एक बड़ा हिस्सा हैं, इसलिए मैं आपको उनके साथ सहज महसूस करने की सलाह देता हूं।

45

मैं जो करता हूं वह मुख्य स्थान से अपडेट प्रबंधित करने के लिए सिंगलटन क्लास को कार्यान्वित करता है। मेरे वर्तमान स्थान तक पहुंचने के लिए, मैं एक CLLocation *myLocation = [[LocationManager sharedInstance] currentLocation]; करते हैं आप मुख्य थ्रेड आप कुछ इस तरह कर सकता है ब्लॉक करने के लिए चाहता था:

while ([[LocationManager sharedInstance] locationKnown] == NO){ 
    //blocking here 
    //do stuff here, dont forget to have some kind of timeout to get out of this blocked //state 
} 

हालांकि, है, क्योंकि यह पहले ही बताया गया है, मुख्य थ्रेड अवरुद्ध शायद नहीं है एक अच्छा विचार है, लेकिन यह एक अच्छा कूदने वाला बिंदु हो सकता है क्योंकि आप कुछ बना रहे हैं। आप यह भी देखेंगे कि मैंने जो कक्षा लिखा है वह स्थान अपडेट पर टाइमस्टैम्प की जांच करता है और पुराने स्थान से पुराने डेटा प्राप्त करने की समस्या को रोकने के लिए पुरानी किसी भी चीज़ को अनदेखा करता है।

यह मैंने लिखा सिंगलटन वर्ग है। कृपया ध्यान दें कि यह किनारों के चारों ओर थोड़ा मोटा है:

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

@interface LocationController : NSObject <CLLocationManagerDelegate> { 
    CLLocationManager *locationManager; 
    CLLocation *currentLocation; 
} 

+ (LocationController *)sharedInstance; 

-(void) start; 
-(void) stop; 
-(BOOL) locationKnown; 

@property (nonatomic, retain) CLLocation *currentLocation; 

@end 
@implementation LocationController 

@synthesize currentLocation; 

static LocationController *sharedInstance; 

+ (LocationController *)sharedInstance { 
    @synchronized(self) { 
     if (!sharedInstance) 
      sharedInstance=[[LocationController alloc] init];  
    } 
    return sharedInstance; 
} 

+(id)alloc { 
    @synchronized(self) { 
     NSAssert(sharedInstance == nil, @"Attempted to allocate a second instance of a singleton LocationController."); 
     sharedInstance = [super alloc]; 
    } 
    return sharedInstance; 
} 

-(id) init { 
    if (self = [super init]) { 
     self.currentLocation = [[CLLocation alloc] init]; 
     locationManager = [[CLLocationManager alloc] init]; 
     locationManager.delegate = self; 
     [self start]; 
    } 
    return self; 
} 

-(void) start { 
    [locationManager startUpdatingLocation]; 
} 

-(void) stop { 
    [locationManager stopUpdatingLocation]; 
} 

-(BOOL) locationKnown { 
    if (round(currentLocation.speed) == -1) return NO; else return YES; 
} 

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { 
    //if the time interval returned from core location is more than two minutes we ignore it because it might be from an old session 
    if (abs([newLocation.timestamp timeIntervalSinceDate: [NSDate date]]) < 120) {  
     self.currentLocation = newLocation; 
    } 
} 

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { 
    UIAlertView *alert; 
    alert = [[UIAlertView alloc] initWithTitle:@"Error" message:[error description] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; 
    [alert show]; 
    [alert release]; 
} 

-(void) dealloc { 
    [locationManager release]; 
    [currentLocation release]; 
    [super dealloc]; 
} 

@end 
+0

इस समाधान के लिए धन्यवाद। यह उपलब्ध कराने के लिए एक अच्छा छोटा नियंत्रक है।हालांकि मुझे मिली एक बात यह थी कि स्थानकन विधि बहुत सटीक नहीं थी - यह हमेशा YES लौटाती है क्योंकि वर्तमान स्थान को init विधि में प्रारंभ किया जाता है। यहां विधि का एक वैकल्पिक संस्करण है जो यह निर्धारित करने के लिए स्पीड प्रॉपर्टी का उपयोग करता है कि उपयोगकर्ता का स्थान प्राप्त हुआ है या नहीं: - (BOOL) स्थान ज्ञात { यदि (गोल (currentLocation.speed) == -1) वापसी नहीं; अन्य वापस यस; } –

+3

मैंने आपका कोड संपादित किया है, उम्मीद है कि मैं इसे सही ढंग से समझ गया हूं। –

+2

आपने केवल संसाधन आवंटित किए हैं लेकिन इसे जारी नहीं किया है। क्या आप कृपया मुझे बता सकते हैं कि आप इसे कहां छोड़ देंगे कि इससे कोई समस्या नहीं आती है। –

7

ऐसी कोई सुविधा नहीं है और आपको अपना खुद का निर्माण नहीं करना चाहिए। "जब तक यह परिणाम न हो जाए तब तक ब्लॉक" आईफोन जैसे डिवाइस पर बेहद खराब प्रोग्रामिंग अभ्यास है। किसी स्थान को पुनर्प्राप्त करने में सेकंड लग सकते हैं; आपको अपने उपयोगकर्ताओं को इस तरह इंतजार नहीं करना चाहिए, और प्रतिनिधियों को यह सुनिश्चित करना चाहिए कि वे नहीं करते हैं।

+1

क्या वह धागा नहीं है? –

+0

धागे, हाँ, जब पूरा होने पर कॉलबैक के साथ संयुक्त हो। जहां कॉलबैक मूल रन लूप पर निर्धारित है। जो आपको पहले से ही CLLocationManager के प्रतिनिधि की तरह इंटरफ़ेस प्राप्त करता है। "किए जाने तक ब्लॉक" अंत उपयोगकर्ता ऐप्स में कभी भी एक अच्छा डिज़ाइन नहीं है। –

+18

मैं असहमत हूं, "किए जाने तक ब्लॉक" के सभी प्रकार के ऐप्स में कई वैध उपयोग हैं, और "पूर्ण होने तक यूआई को फ्रीज" के समानार्थी नहीं हैं। * सब कुछ * एसिंक्रोनस बनाने की कोशिश कर रहा है केवल विचित्र व्यवहार और छोटी गाड़ी के ऐप्स की ओर जाता है। कौन परवाह करता है कि यूआई कितनी तेज़ी से प्रकट होता है/जवाब देता है अगर उसे प्रदर्शित करने की आवश्यकता है तो अभी तक उपलब्ध नहीं है? Async संचालन के पास उनकी जगह है, और इसलिए अवरुद्ध करना। यह ऐसा कोई मामला नहीं है जहां कोई अच्छा है और दूसरा बुरा है। – aroth

0

मैंने ब्रैड स्मिथ द्वारा जवाब की सराहना की। इसे कार्यान्वित करने से मुझे पता चला कि वह जिस तरीके से नियोजित करता है उसे आईओएस 6 के रूप में बहिष्कृत किया जाता है। कोड है कि दोनों iOS5 और iOS6 के साथ काम करेंगे लिखने के लिए, निम्न का उपयोग करें:

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { 
    if (abs([[locations lastObject] timeIntervalSinceDate:[NSDate date]]) < 120) { 
     [self setCurrentLocation:[locations lastObject]]; 
    } 
} 

// Backward compatibility with iOS5. 
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { 
    NSArray *locations = [NSArray arrayWithObjects:oldLocation, newLocation, nil]; 
    [self locationManager:manager didUpdateLocations:locations]; 
} 
0

मैं सरलीकृत और जहां स्थान केवल अद्यतन किया जाता है अगर यह वैध है करने के लिए एकाधिक जवाब संयुक्त।

यह ओएसएक्स के साथ-साथ आईओएस के तहत भी काम करता है।

यह उपयोग-केस मानता है जहां वर्तमान स्थान अचानक उपयोगकर्ता द्वारा वांछित है। यदि इस उदाहरण में 100 एमएस से अधिक समय लगता है, तो इसे एक त्रुटि माना जाता है। (मान लिया गया जीपीएस आईसी & | वाईफ़ाई (एप्पल के Skyhook क्लोन) पहले से ही निकाल दिया जाता है और एक अच्छा ठीक है पहले से ही।)

#import "LocationManager.h" 

// wait up to 100 ms 
CLLocation *location = [LocationManager currentLocationByWaitingUpToMilliseconds:100]; 
if (!location) { 
    NSLog(@"no location :("); 
    return; 
} 
// location is good, yay 

https://gist.github.com/6972228

+0

यह ठीक काम करता है! –

संबंधित मुद्दे