Swiftを使ってみよう
さて、本日はSwiftの勉強を兼ねて、iBeaconのCentralアプリを開発してみようと思います。もちろんiOS8に対応したアプリを開発します。
これまで、筆者はまともにSwiftを触ってきませんでした。しかし、今後の動向を考えるに、Objective-Cだけでなく、Swiftでの開発もできるようになっておかないと技術者として危険な気がするのです。もし、数年後にXcode上でObjective-Cのサポートを終了するということになったら、途端にiPhoneアプリが開発できない技術者となってしまいます。
とは言え、何もなしに書き方を勉強しようとしても辛いものがあります。なので、これまでObjective-Cで開発してきたアプリをSwiftに移行するという方法でSwiftを学んでいくこととしました。
では、早速、開発を進めていきましょう!
本ブログでは、Objective-CとSwiftでの書き方を比較しながら進めていきます。
Objective-Cとの比較が不要な方はSwiftの場合の項目のみを読んでください。
ライブラリのimport
1
2
| // ViewController.hファイル
#import <UIKit/UIKit.h>
|
1
2
3
| // ViewController.mファイル
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
|
1
2
3
| // ViewController.swiftファイル
import UIKit
import CoreLocation
|
インスタンス変数の宣言
- Objective-Cの場合
Objective-Cの場合は
import
のすぐ下のinterface内で書きます。
1
2
3
4
5
6
7
8
9
10
| // ViewController.mファイル
@interface ViewController ()
@property (strong, nonatomic) CLLocationManager *locationManager;
@property (strong, nonatomic) NSUUID *proximityUUID;
@property (strong, nonatomic) CLBeaconRegion *beaconRegion;
@property (strong, nonatomic) CLBeacon *nearestBeacon;
@property (strong, nonatomic) NSString *str;
@end
|
- Swiftの場合
Swiftの場合はclass ViewController
に全体が囲まれる書式になるため、class ViewController
のすぐ下に書きます。
1
2
3
4
5
6
7
8
9
10
11
| class ViewController: UIViewController {
var locationManager:CLLocationManager?
var proximityUUID:NSUUID?
var beaconRegion:CLBeaconRegion?
var nearestBeacon:CLBeacon?
var str:NSString?
.....
}
|
Delegate Protocolの宣言
1
2
3
| @interface ViewController() <CLLocationManagerDelegate, UIAlertViewDelegate> {
.....
}
|
1
2
3
| class ViewController: UIViewController, CLLocationManagerDelegate, UIAlertViewDelegate {
.....
}
|
viewDidLoadメソッド
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| - (void)viewDidLoad {
[super viewDidLoad];
if ([CLLocationManager isMonitoringAvailableForClass:[CLCircularRegion class]]) {
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.proximityUUID = [[NSUUID alloc] initWithUUIDString:@"UUID文字列を指定"];
self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID: self.proximityUUID identifier:@"Objective-C iBeacon"];
if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
[self.locationManager requestAlwaysAuthorization];
} else {
[self.locationManager startMonitoringForRegion: self.beaconRegion];
}
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"確認" message:@"お使いの端末ではiBeaconを利用できません。" delegate:self cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
[alert show];
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| override func viewDidLoad() {
super.viewDidLoad()
if(CLLocationManager.isMonitoringAvailableForClass(CLCircularRegion)) {
self.locationManager = CLLocationManager()
self.locationManager?.delegate = self
self.proximityUUID = NSUUID(UUIDString: "UUID文字列を指定")
self.beaconRegion = CLBeaconRegion(proximityUUID: self.proximityUUID, identifier: "Swift iBeacon")
if((self.locationManager?.respondsToSelector("requestAlwaysAuthorization")) != nil) {
self.locationManager?.requestAlwaysAuthorization()
} else {
self.locationManager?.startMonitoringForRegion(self.beaconRegion)
}
} else {
var alert:UIAlertView? = UIAlertView(title: "確認",message: "お使いの端末ではiBeaconを利用できません。", delegate: self, cancelButtonTitle: nil, otherButtonTitles: "OK")
alert?.show()
}
}
|
自作メソッドの定義
ここではローカルプッシュを送信するメソッドを定義します。
1
2
3
4
5
6
7
8
| - (void)sendLocalNotificationForMessage:(NSString *)message
{
UILocalNotification *localNotification = [UILocalNotification new];
localNotification.alertBody = message;
localNotification.fireDate = [NSDate date];
localNotification.soundName = UILocalNotificationDefaultSoundName;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
}
|
1
2
3
4
5
6
7
| func sendLocalNotificationForMessage(message: NSString!) {
var localNotification:UILocalNotification = UILocalNotification()
localNotification.alertBody = message
localNotification.fireDate = NSDate.date()
localNotification.soundName = UILocalNotificationDefaultSoundName
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
}
|
CLLocationManagerのDelegateメソッド
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
| // 領域計測が開始した場合
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region
{
[self sendLocalNotificationForMessage:@"Start Monitoring Region"];
}
// 領域に侵入した場合
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
[self sendLocalNotificationForMessage:@"Enter Region"];
if ([region isMemberOfClass:[CLBeaconRegion class]] && [CLLocationManager isRangingAvailable]) {
[self.locationManager startRangingBeaconsInRegion:(CLBeaconRegion *)region];
}
}
// 領域から退出した場合
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
[self sendLocalNotificationForMessage:@"Exit Region"];
if ([region isMemberOfClass:[CLBeaconRegion class]] && [CLLocationManager isRangingAvailable]) {
[self.locationManager stopRangingBeaconsInRegion:(CLBeaconRegion *)region];
}
}
// 領域内にいるかいないかの判断
-(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region{
switch (state) {
case CLRegionStateInside:
if([region isMemberOfClass:[CLBeaconRegion class]] && [CLLocationManager isRangingAvailable]){
NSLog(@"Enter %@",region.identifier);
//Beacon の範囲内に入った時に行う処理を記述する
[self sendLocalNotificationForMessage:@"Already Entering"];
}
break;
case CLRegionStateOutside:
case CLRegionStateUnknown:
default:
break;
}
}
// 距離計測
- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region
{
if (beacons.count > 0) {
//CLBeacon *nearestBeacon = beacons.firstObject;
self.nearestBeacon = beacons.firstObject;
NSString *rangeMessage;
switch (self.nearestBeacon.proximity) {
case CLProximityImmediate:
rangeMessage = @"Range Immediate";
break;
case CLProximityNear:
rangeMessage = @"Range Near";
break;
case CLProximityFar:
rangeMessage = @"Range Far";
break;
default:
rangeMessage = @"Range Unknown";
break;
}
self.str = [[NSString alloc] initWithFormat:@"%f [m]", self.nearestBeacon.accuracy];
[self sendLocalNotificationForMessage:self.str];
}
}
// 領域観測に失敗した場合
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error
{
[self sendLocalNotificationForMessage:@"Exit Region"];
}
// 位置情報の許可設定
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
if (status == kCLAuthorizationStatusNotDetermined) {
} else if(status == kCLAuthorizationStatusAuthorizedAlways) {
[self.locationManager startMonitoringForRegion: self.beaconRegion];
} else if(status == kCLAuthorizationStatusAuthorizedWhenInUse) {
[self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
| // 領域観測が開始した場合
func locationManager(manager: CLLocationManager!, didStartMonitoringForRegion region: CLRegion!) {
self.sendLocalNotificationForMessage("Start Monitoring Region")
}
// 領域に侵入した場合
func locationManager(manager: CLLocationManager!, didEnterRegion region: CLRegion!) {
self.sendLocalNotificationForMessage("Enter Region")
if(region.isMemberOfClass(CLBeaconRegion) && CLLocationManager.isRangingAvailable()) {
self.locationManager?.startRangingBeaconsInRegion(region as CLBeaconRegion)
}
}
// 領域から退出した場合
func locationManager(manager: CLLocationManager!, didExitRegion region: CLRegion!) {
self.sendLocalNotificationForMessage("Enter Region")
if(region.isMemberOfClass(CLBeaconRegion) && CLLocationManager.isRangingAvailable()) {
self.locationManager?.stopRangingBeaconsInRegion(region as CLBeaconRegion)
}
}
// 領域内にいるかどうかの判断
func locationManager(manager: CLLocationManager!, didDetermineState state: CLRegionState, forRegion region: CLRegion!) {
switch(state) {
case .Inside:
if(region.isMemberOfClass(CLBeaconRegion) && CLLocationManager.isRangingAvailable()) {
self.locationManager?.startRangingBeaconsInRegion(region as CLBeaconRegion)
}
break
case .Outside:
break
case .Unknown:
break
default:
break
}
}
// 距離計測
func locationManager(manager: CLLocationManager!, didRangeBeacons beacons: [AnyObject]!, inRegion region: CLBeaconRegion!) {
if(beacons.count > 0) {
self.nearestBeacon = beacons[0] as? CLBeacon
var proximity:CLProximity! = self.nearestBeacon?.proximity
var bAccuracy:CLLocationAccuracy! = self.nearestBeacon?.accuracy
var rangeMessage:NSString
if(proximity == CLProximity.Immediate) {
rangeMessage = "Range Immediate"
} else if(proximity == CLProximity.Near) {
rangeMessage = "Range Near"
} else if(proximity == CLProximity.Far) {
rangeMessage = "Range Far"
} else if(proximity == CLProximity.Unknown) {
rangeMessage = "Range Unknown"
}
self.str = "\(bAccuracy) [m]"
self.sendLocalNotificationForMessage(self.str)
}
}
// 領域観測に失敗した場合
func locationManager(manager: CLLocationManager!, monitoringDidFailForRegion region: CLRegion!, withError error: NSError!) {
self.sendLocalNotificationForMessage("Exit Region")
}
// 位置情報の許可設定
func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if(status == .NotDetermined) {
} else if(status == .Authorized) {
self.locationManager?.startMonitoringForRegion(self.beaconRegion)
} else if(status == .AuthorizedWhenInUse) {
self.locationManager?.startRangingBeaconsInRegion(self.beaconRegion)
}
}
|
以上でコーディング終了です。Objective-Cのときと同様にSwiftでもBeaconを検知することができるようになりました。
Swiftの勉強がてら、こういった取り組みを進めていこうと思います。
本日はここまで。
参考:
SwiftとiBeaconを使ってお母さんが自分の部屋に近づいて来た事を警告するアプリをつくる
Objective-C で書いたアプリを Swift で書き換える5ステップ