2015年1月30日 星期五

台灣繁中Concurrency Programming Guide (I)

Introduction

Concurrency(共時性)是一種概念,它想表達的是許多事情在同一個時間點發生。隨著多核心CPU的發展,軟體開發者需要用新的方式以便對CPU做更好的使用。雖然像OS X和iOS的作業系統能夠同時執行許多程式,但是其中大部份的程式是以背景方式執行且只向作業系統要求很短的「連續處理時間」。而造成電腦忙碌的是使用者正在前景執行的程式。如果一個應用軟體很忙碌,而你又只允許給它小部分的核心資源,那大部分的資源就會因為閒置造成浪費。
在過去,要實作程式的concurrency需要建立一個以上的thread,撰寫有關thread的程式碼又是相當的困難,因為thread是屬於比較低階的工具,所以都要手動去管理,想要給定理想的thread數量,需要考慮到目前系統的負荷跟硬體的規格等等。更慘的是,用來處理thread之間的同步機制,常常會增加軟體設計的複雜度和風險,但卻不能保證一定會有更好的效能。 
OS X跟iOS都採用了相較於傳統使用thread方式更加非同步的方法來實作concurrent的事件,比起直接創建一個thread,應用程式只需定義你想要做concurrent的事件然後讓系統自行去管理,如此一來,應用程式的擴展性會比原來的thread用法好的多!開發者也會得到更簡單而有效率的編寫concurrent程式的模型。 
這份文件會教你在程式中實作concurrency的一些技巧和技術,這些技術在OS X和iOS中都是可以通用的。

Organization of This Document

這份文件包含下列幾個章節:
這份文件也提供了相關術語的詞彙表。





A Note About Terminology

在深入討論concurrency之前,有必要先定義一些相關術語來避免混淆。比較熟悉UNIX系統或舊式OS X的開發者們會發現這些術語 “task”, “process”, “thread” 在這份文件中的用法有點不同。這件文件中的用法如下所示:
  • thread :表示程式碼在不同的路徑的執行過程。在OS X中是由POSIX threads API來實作。
  • process :表示正在執行的程式,裡面包含很多thread。
  • task :是一個抽象概念,用來表示你需要完成的工作。
若想了解這些術語的完整定義,以及其他術語的用法,請參照術語詞彙表(Glossary).


See Also

這份文件將重點放在如何在你的app中實作concurrency,而未包含如果使用threads,如果你想了解如何使用thread,你可以參考另外這份文件 Threading Programming Guide.

2014年7月9日 星期三

台灣繁中Location and Maps Programming Guide

Region Monitoring and iBeacon

The Core Location framework 提供兩種方式來偵測使用者進入與離開特定區域:
一, geographical region monitoring (iOS 4.0 and later and OS X v10.8 and later) 
二, beacon region monitoring (iOS 7.0 and later). 
geographical region 是一個地表上的圓,你可以給定半徑和圓心座標。
相反的, a beacon region 被定義為一個BLE的訊號範圍的區域。 Beacons本身是一個廣播特定訊號的簡單的裝置,你甚至可以用你的iOS device做為iBeacon,只要使用 Core Bluetooth framework.
Apps可以使用地區監控,在使用者經過指定地區或者進入/離開beacon範圍時發出通知。當beacon進入iOS device範圍時,app可以監控目前跟beacon的距離。你可以利用這個功能來開發許多不同類型的定位app。
因為地理區域與beacon區域是不同的,所以你要根據你的app的需求來決定要用那一種區域監控。
在iOS中,區域監控是全時段的,包括app沒有被執行時。如果進入區域的時app沒有被啟動。那app會被在背景開啟去處理這次的事件。同樣地,如果app是暫時進入背景,app也會被喚醒一小段時間(大約十秒鐘)來處理這次的事件。當仍有需要時,app可以用 UIApplication 類別的 beginBackgroundTaskWithExpirationHandler: 方法來要求更多的背景執行時間。
在OS X中, 區域監控只可在app被啟動之後使用(不論前景或背景)使用者的系統必需要被喚醒。結論是系統不能自動開啟app去傳送區域相關的通知。



Determining the Availability of Region Monitoring

Before attempting to monitor any regions, your app should check whether region monitoring is supported on the current device. Here are some reasons why region monitoring might not be available:
  • The device doesn’t have the necessary hardware to support region monitoring.
  • The user denied the app the authorization to use region monitoring.
  • The user disabled location services in the Settings app.
  • The user disabled Background App Refresh in the Settings app, either for the device or for your app.
  • The device is in Airplane mode and can’t power up the necessary hardware.
In iOS 7.0 and later, always call the isMonitoringAvailableForClass: and authorizationStatus class methods of CLLocationManagerbefore attempting to monitor regions. (In OS X v10.8 and later and in previous versions of iOS, use the regionMonitoringAvailable class instead.) The isMonitoringAvailableForClass: method tells you whether the underlying hardware supports region monitoring for the specified class at all. If that method returns NO, your app can’t use region monitoring on the device. If it returns YES, call the authorizationStatusmethod to determine whether the app is currently authorized to use location services. If the authorization status iskCLAuthorizationStatusAuthorized, your app can receive boundary crossing notifications for any regions it registered. If the authorization status is set to any other value, the app doesn’t receive those notifications.



Finally, if your app needs to process location updates in the background, be sure to check the backgroundRefreshStatus property of theUIApplication class. You can use the value of this property to determine if doing so is possible and to warn the user if it is not. Note that the system doesn’t wake your app for region notifications when the Background App Refresh setting is disabled globally or specifically for your app.

Monitoring Geographical Regions

Geographical region monitoring uses location services to detect entry and exit into known geographical locations (learn more about location services in “Getting the User’s Location”). You can use this capability to generate alerts when the user gets close to a specific location or to provide other relevant information. For example, upon approaching a specific dry cleaners, an app could notify the user to pick up any clothes that are now ready.

Defining a Geographical Region to Be Monitored

To begin monitoring a geographical region, you must define the region and register it with the system. In iOS 7.0 and later, you define geographical regions using the CLCircularRegion class. (In OS X v10.8 and later and in previous versions of iOS, you use the CLRegion class instead.) Each region you create must include both the data that defines the desired geographic area and a unique identifier string. The identifier string is the only guaranteed way for your app to identify a region later. To register a region, call the startMonitoringForRegion: method of your CLLocationManager object.
Listing 2-1 shows a sample method that creates a new geographic region based on a circular overlay region. The overlay’s center point and radius form the boundary for the region, although if the radius is too large to be monitored, it is reduced automatically. You don’t need to save strong references to the regions you create but might want to store the region’s identifier if you plan to access the region information later.
Listing 2-1  Creating and registering a geographical region based on a Map Kit overlay
- (void)registerRegionWithCircularOverlay:(MKCircle*)overlay andIdentifier:(NSString*)identifier {
 
   // If the overlay's radius is too large, registration fails automatically,
   // so clamp the radius to the max value.
   CLLocationDegrees radius = overlay.radius;
   if (radius > self.locManager.maximumRegionMonitoringDistance) {
      radius = self.locManager.maximumRegionMonitoringDistance;
   }
 
   // Create the geographic region to be monitored.
   CLCircularRegion *geoRegion = [[CLCircularRegion alloc]
      initWithCenter:overlay.coordinate
              radius:radius
          identifier:identifier];
   [self.locManager startMonitoringForRegion:geoRegion];
}
Monitoring of a geographical region begins immediately after registration for authorized apps. However, don’t expect to receive an event right away, because only boundary crossings generate an event. In particular, if the user’s location is already inside the region at registration time, the location manager doesn’t automatically generate an event. Instead, your app must wait for the user to cross the region boundary before an event is generated and sent to the delegate. To check whether the user is already inside the boundary of a region, use the requestStateForRegion:method of the CLLocationManager class.
Be judicious when specifying the set of regions to monitor. Regions are a shared system resource, and the total number of regions available systemwide is limited. For this reason, Core Location limits to 20 the number of regions that may be simultaneously monitored by a single app. To work around this limit, consider registering only those regions in the user’s immediate vicinity. As the user’s location changes, you can remove regions that are now farther way and add regions coming up on the user’s path. If you attempt to register a region and space is unavailable, the location manager calls the locationManager:monitoringDidFailForRegion:withError: method of its delegate with thekCLErrorRegionMonitoringFailure error code.

Handling Boundary-Crossing Events for a Geographical Region

By default, every time a user’s current location crosses a boundary region, the system generates an appropriate region event for your app. Apps can implement the following methods to handle boundary crossings:
You can customize which boundary-crossing events notify your app by explicitly setting the notifyOnEntry and notifyOnExit properties of theCLRegion class when you define and register a region. (The default value of both properties is YES.) For example, if you want to be notified only when the user exits the boundary of a region, you can set the value of the region’s notifyOnEntry property to NO.
The system doesn’t report boundary crossings until the boundary plus a system-defined cushion distance is exceeded. This cushion value prevents the system from generating numerous entered and exited events in quick succession while the user is traveling close the edge of the boundary.
When a region boundary is crossed, the most likely response is to alert the user of the proximity to the target item. If your app is running in the background, you can use local notifications to alert the user; otherwise, you can simply post an alert.

Monitoring Beacon Regions

Beacon region monitoring uses an iOS device’s onboard radio to detect when the user is in the vicinity of Bluetooth low-energy devices that are advertising iBeacon information. As with geographical region monitoring, you can use this capability to generate alerts or to provide other relevant information when the user enters or exits a beacon region. Rather than being identified by fixed geographical coordinates, however, a beacon region is identified by the device’s proximity to Bluetooth low-energy beacons that advertise a combination of the following values:
  • proximity UUID (universally unique identifier), which is a 128-bit value that uniquely identifies one or more beacons as a certain type or from a certain organization
  • major value, which is a 16-bit unsigned integer that can be used to group related beacons that have the same proximity UUID
  • minor value, which is a 16-bit unsigned integer that differentiates beacons with the same proximity UUID and major value
Because a single beacon region can represent multiple beacons, beacon region monitoring supports several interesting use cases. For example, an app dedicated to enhancing the experience of customers at a particular department store can use the same proximity UUID to monitor all stores in the department store chain. When the user approaches a store, the app detects the store’s beacons and uses the major and minor values of those beacons to determine additional information, such as which specific store was encountered or which section of the store the user is in. (Note that although every beacon must advertise a proximity UUID, major and minor values are optional.)

Defining a Beacon Region to Be Monitored

To begin monitoring a beacon region, define the region and register it with the system. You define a beacon region with the appropriate initialization method of the CLBeaconRegion class. When you create a CLBeaconRegion object, you specify the proximityUUIDmajor, andminor properties of the beacons you want to monitor (the proximity UUID is required; the major and minor values are optional). You must also supply a string that uniquely identifies the region so that you can refer to it in your code. Note that a region’s identifier is unrelated to the identifying information that a beacon advertises.
To register a beacon region, call the startMonitoringForRegion: method of your CLLocationManager object. Listing 2-2 shows a sample method that creates and registers a beacon region.
Listing 2-2  Creating and registering a beacon region
- (void)registerBeaconRegionWithUUID:(NSUUID *)proximityUUID andIdentifier:(NSString*)identifier {
 
   // Create the beacon region to be monitored.
   CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc]
      initWithProximityUUID:proximityUUID
                 identifier:identifier];
 
   // Register the beacon region with the location manager.
   [self.locManager startMonitoringForRegion:beaconRegion];
}
As with geographical region monitoring, monitoring of a beacon region begins immediately after registration for authorized apps. When a user’s device detects a beacon that is advertising the identifying information defined by the registered beacon region (proximity UUID, major value, and minor value), the system generates an appropriate region event for your app.



Handling Boundary-Crossing Events for a Beacon Region

When a user enters the registered beacon region, the location manager calls the locationManager:didEnterRegion: of its delegate object. Similarly, when a user is no longer in range of any beacons in the registered beacon region, the location manager calls thelocationManager:didExitRegion: of its delegate object. Note that a user must cross the region’s boundary to trigger one of these calls; in particular, the location manager doesn’t call locationManager:didEnterRegion: if the user is already within the region. You can implement these delegate methods to alert the user appropriately or to present location-specific UI.
You can specify which boundary-crossing events should notify your app by setting the notifyOnEntry and notifyOnExit properties of the beacon region. (The default value of both properties is YES.) For example, if you want to be notified only when the user exits the boundary of a region, you can set the value of the region’s notifyOnEntry property to NO.
You can also postpone notifying a user upon entering a beacon region until the user turns on the device’s display. To do so, simply set the value of the beacon region’s notifyEntryStateOnDisplay property value to YES and set the region’s notifyOnEntry property to NO when you register the beacon region. To prevent redundant notifications from being delivered to the user, post a local notification only once per region entry.

Determining the Proximity of a Beacon Using Ranging

While a user’s device is inside a registered beacon region, apps can use the startRangingBeaconsInRegion: method of the CLLocationManagerclass to determine the relative proximity of one or more beacons in the region and to be notified when that distance changes. (Always call theisRangingAvailable class method of the CLLocationManager class before attempting to range beacons in a beacon region.) Knowing the relative distance to a beacon can be useful for many apps. For example, imagine a museum that places a beacon at each exhibit. A museum-specific app could use a particular exhibit’s proximity as a cue to provide information about that exhibit rather than another.
The location manager calls the locationManager:didRangeBeacons:inRegion: of its delegate object whenever beacons in the specified beacon region come within range, go out of range, or their proximity changes. This delegate method provides an array of CLBeacon objects that represent the beacons currently in range. The array of beacons is ordered by approximate distance from the device, with the closest beacon at the beginning of the array. You can use the information in these objects to determine the proximity of the user to each beacon. The value in the proximityproperty of the CLBeacon object gives a general sense of the relative distance to a beacon.



Inspired by the sample museum app described earlier in this section, Listing 2-3 shows how to use a beacon’s proximity property to determine its relative distance from the user’s device. The code presents a UI that provides more information about a particular museum exhibit when the proximity of the closest beacon in the array is relatively close to the user (as defined by the CLProximityNear constant).
Listing 2-3  Determining the relative distance between a beacon and a device
// Delegate method from the CLLocationManagerDelegate protocol.
- (void)locationManager:(CLLocationManager *)manager
        didRangeBeacons:(NSArray *)beacons
               inRegion:(CLBeaconRegion *)region {
 
   if ([beacons count] > 0) {
      CLBeacon *nearestExhibit = [beacons firstObject];
 
      // Present the exhibit-specific UI only when
      // the user is relatively close to the exhibit.
      if (CLProximityNear == nearestExhibit.proximity) {
         [self presentExhibitInfoWithMajorValue:nearestExhibit.major.integerValue];
      } else {
         [self dismissExhibitInfo];
   }
}
To promote consistent results in your app, use beacon ranging only while your app is in the foreground. If your app is in the foreground, it is likely that the device is in the user’s hand and that the device’s view to the target beacon has fewer obstructions. Running in the foreground also promotes better battery life by processing incoming beacon signals only while the user is actively using the device.



Turning an iOS Device into an iBeacon

Any iOS device that supports sharing data using Bluetooth low energy can be used as an iBeacon. Because the app you write must run in the foreground, iBeacon support on iOS devices is intended for testing purposes and for apps that always run in the foreground anyway, such as point-of sale apps. For other types of iBeacon implementations, you need to acquire dedicated beacon hardware from third-party manufacturers.
Because turning your iOS device into a beacon requires the use of the Core Bluetooth framework, be sure to link your app toCoreBluetooth.framework in your Xcode project. To access the classes and headers of the framework, include an #import <CoreBluetooth/CoreBluetooth.h> statement at the top of any relevant source files.

Creating and Advertising a Beacon Region

To use your iOS device as a beacon, you first generate a 128-bit UUID that will be your beacon region’s proximity UUID. Open Terminal and typeuuidgen on the command line. You receive a unique 128-bit value in an ASCII string that is punctuated by hyphens, as in this example.
$ uuidgen
39ED98FF-2900-441A-802F-9C398FC199D2
Next, create a beacon region with the UUID you generated for the beacon’s proximity UUID, defining the major and minor values as needed. Be sure to also use a unique string identifier for the new region. This code shows how to create a new beacon region using the example UUID above.
   NSUUID *proximityUUID = [[NSUUID alloc]
      initWithUUIDString:@"39ED98FF-2900-441A-802F-9C398FC199D2"];
 
   // Create the beacon region.
   CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc]
      initWithProximityUUID:proximityUUID
                 identifier:@"com.mycompany.myregion"
Now that you have created a beacon region, you need to advertise your beacon’s proximity UUID (and any major or minor value you specified) using the CBPeripheralManager class of the Core Bluetooth framework. In Core Bluetooth, a peripheral is a device that advertises and shares data using Bluetooth low energy. Advertising your beacon’s data is the only way other devices can detect and range your beacon.
To advertise peripheral data in Core Bluetooth, you call the startAdvertising: method of the CBPeripheralManager class on an instance of aCBPeripheralManager object. This method expects a dictionary (an instance of NSDictionary) of advertisement data. As the next example shows, use the peripheralDataWithMeasuredPower: method of the CLBeaconRegion class to receive a dictionary that encodes your beacon’s identifying information along with other information needed for Core Bluetooth to advertise the beacon as a peripheral.
   // Create a dictionary of advertisement data.
   NSDictionary *beaconPeripheralData =
      [beaconRegion peripheralDataWithMeasuredPower:nil];



Next, create an instance of the CBPeripheralManager class, and ask it to advertise your beacon for other devices to detect, as shown in the code below.
   // Create the peripheral manager.
   CBPeripheralManager *peripheralManager = [[CBPeripheralManager alloc]
      initWithDelegate:selfqueue:nil options:nil];
 
   // Start advertising your beacon's data.
   [peripheralManager startAdvertising:beaconPeripheralData];



After advertising your app as a beacon, your app must continue running in the foreground to broadcast the needed Bluetooth signals. If the user quits the app, the system stops advertising your device as a peripheral.
For more information about how to use a peripheral manager to advertise data using Bluetooth low energy, see CBPeripheralManager Class Reference and Core Bluetooth Programming Guide.

Testing an iOS App’s Region Monitoring Support

When testing your region monitoring code in iOS Simulator or on a device, realize that region events may not happen immediately after a region boundary is crossed. To prevent spurious notifications, iOS doesn’t deliver region notifications until certain threshold conditions are met. Specifically, the user’s location must cross the region boundary, move away from the boundary by a minimum distance, and remain at that minimum distance for at least 20 seconds before the notifications are reported.
The specific threshold distances are determined by the hardware and the location technologies that are currently available. For example, if Wi-Fi is disabled, region monitoring is significantly less accurate. However, for testing purposes, you can assume that the minimum distance is approximately 200 meters.

台灣繁中CLLocationManager Class Reference

CLLocationManager Class Reference

Inherits from
Conforms to
Framework
/System/Library/Frameworks/CoreLocation.framework
Availability
Available in iOS 2.0 and later.
Companion guide
Declared in
CLLocation.h
CLLocationManager.h
Related sample code


總覧
The CLLocationManager class 定義一個界面讓你可以去設定和"地點移點"和"方向改變"相關的事件。你要用一個CLLocationManager的實體來設定何時要接受 "地點移點"和"方向改變"的事件,並可以接收地點和方向的相關資料。
地點管理物件提供下列支援:
  • 追踪使用者的目前位置,並可以調整GPS的精確度。
  • 報告目前方向計的方向. (iOS only)
  • 監控你想監控的區域,並回報進入和離開的資訊.
  • 當app進入背景時,會延遲傳送地點更新. (iOS 6 and later only)
  • 報告出附近的beacons的範圍.
有些定位服務需要在iDevice上特定的硬體,例如方向資訊必需要有方向計,CLLocationManager class定義了一些方法讓你可以去得知這些服務在你的裝置上可否使用。

關於要使用這種服務,你應該先設定跟精準度有關的參數,因為裝置會為了省電而主動的關掉不需要用到的硬體。舉例來說,把精準度設定為一公里,可以給location manager一個彈性範圍去決定是否關掉GPS定位而直接採用WiFi或手機訊息,因為關閉GPS能明顯的省電。
設定和使用CLLocationManager 物件來傳遞事件:
  1. 永遠記得要在使用該服務前先檢查該裝置是否有執行該服務,如果沒有就不要使用它。
  2. 建立一個the CLLocationManager class的實體.
  3. 指派你的物件給delegate去呼叫,這個物件必須符合CLLocationManagerDelegate 協定.
  4. 設定每個你想到使用的service的相關properties。
  5. 呼叫你想啟用的service的啟用method。
所以地點和方向的更新都會傳送給你指派的delegate物件,這些delegate的callback你可以參考 CLLocationManagerDelegate Protocol Reference.

取得使用者目前的定位
設定地點相關的服務有二種選擇:
  • 使用標準定位服務,它允許你設定想要的地理資訊精確度,當地點更新時會接到訊息。標準定位服務可以在iOS的所有版本上使用、和10.6以上的OSX上使用。
  • 需求事件只在地點有明顯的改變時發生作用,它提供少數幾個追踪的選擇,但卻提供大量省電方案和在你的app未執行時仍能更新地點資訊的能力。這項服務只在iOS4.0以上的版本才有提供,而且裝置必需能用3G的功能。
要啟用標準定位服務,你要呼叫startUpdatingLocation 方法. 這項服務適合用在需要精細地點更新資訊的App上。具體來說,這項服務把 desiredAccuracy 和 distanceFilter 這兩個property加入決定是否傳送更新資訊的考量。 導航app和其他定期更新位置的app都需要用精確的標準定位服務。然而,這項服務需要一直開著定位追踪的硬體,這會造成耗電量大增。
如果你的app不需要定期更新地點資訊,你可以考慮使用startMonitoringSignificantLocationChanges 方法來啟用定位事件的傳送。這個方法更適用於當你只需要先定義初始位置,之後要在明確的位置改變時,再傳送下一次的更新訊息。這個介面只在它偵測到3G基地台改變時才發出訊息。
不論你是用那一種定位服務,位置的資料都會透過相關的delegate回傳給你。因為它在初始化位置時會花上幾秒鐘的時間,所以通常location manager會立刻先丟給你它上一次cache下來的位置資料,等它初始化完成之後才會傳送當下的即時資料。因此,最好先確定位置資料的timestamp是你要的之後,再拿來使用。如果有二個location services被同步啟用,那它們會把資料都傳進相同的delegate實作方式之中。
在iOS 6之後,你可以把在進入背景之後的位置資料都延遲處理,最後再一次傳送給delegate方法,建議當你的app可以一次處理先前的資料時,就使用這個機制,例如app要追踪登山者的路線,就可以先不用使用app,等過了一定距離再一次計算,這可以讓你的app更加的省電。

Using Regions to Monitor Boundary Crossings

In iOS 4.0 and later and OS X 10.8 and later, you can use the region-monitoring service to define the boundaries for multiple geographical regions. After registering a region using the startMonitoringForRegion: method, the location manager tracks movement across the region’s boundary and reports that movement to its delegate. You might use region monitoring to alert the user to approaching landmarks or to provide other relevant information. For example, upon approaching a dry cleaners, an application could notify the user to pick up any clothes that had been dropped off and are now ready.
In iOS, the regions you register with the location manager persist between launches of your application. If a region crossing occurs while your iOS app is not running, the system automatically wakes it up (or relaunches it) in the background so that it can process the event. When relaunched, all of the regions you configured previously are made available in the monitoredRegions property of any location manager objects you create.
In OS X, region monitoring works only while the app is running (either in the foreground or background) and the user’s system is awake. The system does not launch apps to deliver region-related notifications. Similarly, if the user puts the computer to sleep, the system does not deliver region monitoring notifications to your app. If the user wakes up the computer inside a monitored region, the system does deliver region notifications to your app if it is running. However, if the computer enters and exits the region before being woken up, no notification is delivered.


The region monitoring service operates independently of any location services in use by your application, and you may use it in conjunction with any of the other services. Region monitoring is not supported on all devices. Use theregionMonitoringAvailable class method to determine if region monitoring can be used.

Configuring Heading-Related Services

In iOS, a device with the appropriate hardware may also report heading information. When the value in theheadingAvailable property is YES, you can use a location manager object to retrieve heading information. To begin the delivery of heading-related events, assign a delegate to the location manager object and call the location manager’s startUpdatingHeading method. If location updates are also enabled, the location manager returns both the true heading and magnetic heading values. If location updates are not enabled, the location manager returns only the magnetic heading value. These features are not available in OS X.