このエントリーをはてなブックマークに追加
ラベル Swift の投稿を表示しています。 すべての投稿を表示
ラベル Swift の投稿を表示しています。 すべての投稿を表示

2017年2月10日金曜日

Swift3でSCLAlertViewを使ってみた

こんにちは、onukiです。

今回はSwiftでフラットなデザインの
アニメーション付きアラートビューが扱える
SCLAlertViewを試してみたいと思います。

準備

おなじみCocoaPodでインストールします。
pod 'SCLAlertView'

実装

今回はボタン付きのアラートを表示したいと思います。
まずはSCLAlertViewをインポートします。
import SCLAlertView
アラートビューを表示します、ボタンは二つ用意します。
let alertView = SCLAlertView()
//ボタンの追加
alertView.addButton("ボタン1") {
    //タップ時の処理
    print("ボタン1をタップしました")
}
alertView.addButton("ボタン2") {
    print("ボタン2をタップしました")
}
//表示実行
alertView.showSuccess("ボタン付きアラート", subTitle: "説明")
そうするとこのように表示されます。

今回は基本的なボタン付きのアラートでしたが、
他にもテキスト入力できるもの、ボタンなしで時間指定で閉じるもの等
色々あるので、興味を持たれた方は作者のgithubを拝見してみてください。

2017年2月4日土曜日

Swift3でLTMorphingLabelを使ってみた

こんにちは、onukiです。

今回はLTMorphingLabelというライブラリが
面白そうなので使ってみました。

LTMorphingLabelとは


ラベルのテキスト変更時にエフェクトをつけてくれるライブラリです。
作者のgithubにエフェクトのサンプルがあるのですが、
見ているだけで試してみたい欲に駆られますね。

準備


今回はCocoaPodsで追加します。
ただし、現在Swift3ではブランチの指定をしないと
ビルドが通らないみたいなので気をつけて下さい。
pod 'LTMorphingLabel', :git => 'https://github.com/lexrus/LTMorphingLabel.git', :branch => 'swift3'

実装


まずはLTMorphingLabelをimportします。
import LTMorphingLabel

StoryboardにUILabelを適当に用意し
ClassにLTMorphingLabelを指定してください。
それをIBOutlet接続します。
@IBOutlet weak var morphingLabel: LTMorphingLabel!

エフェクトの定義を行います。
morphingLabel.morphingEffect = .evaporate
エフェクトの種類、サンプルに関しては作者のgithubを参照してください。

これでmorphingLabelのtextを変更すると
エフェクトがかかるようになります。

これだけだとイマイチエフェクトの切り替わりを実感できないのでTimerで
morphingLabelのtextを更新するようにしてみたいと思います。
    @IBOutlet weak var morphingLabel: LTMorphingLabel!
    
    //表示制御用タイマー
    private var timer: Timer?
    //String配列のindex用
    private var index: Int = 0
    //表示するString配列
    private let textList = ["シンプルであることは、", "複雑であることよりも", "難しい"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // エフェクトの定義
        morphingLabel.morphingEffect = .evaporate
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        //タイマーの追加
        timer = Timer.scheduledTimer(timeInterval: 3.0,
                                     target: self,
                                     selector: #selector(update(timer:)), userInfo: nil,
                                     repeats: true)
        timer?.fire()
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        
        timer?.invalidate()
    }
    
    func update(timer: Timer) {
        //ここでtextの更新
        morphingLabel.text = textList[index]
        
        index += 1
        if index >= textList.count {
            index = 0
        }
    }
これでLTMorphingLabelのエフェクトを堪能できると思います。

実装も簡単ですし、見た目も素晴らしいので色々使ってみたいですね。

2017年2月3日金曜日

Swift3でTTTAttributedLabelリンク表示の指定をやってみた

こんにちは、onukiです。

以前、TTTAttributedLabelでのリンク表示を紹介しましたが
今回は応用でLabelにリンクを表示したくない時などに使える
リンク表示の指定をやって見たいと思います。

準備

前回の記事を参照してください。

実装

今回は表示の文字列から「URL」の部分をタップできるようにします。
//リンクをタップできるように設定
linkLabel.enabledTextCheckingTypes = NSTextCheckingResult.CheckingType.link.rawValue
//リンクのタップを制御するために設定
linkLabel.delegate = self
let label = "URLをタップできます。"
linkLabel.text = label
//labelから“URL”を部分を選択
let range = NSRange.init(location: 0, length: 3)
//タップした時の接続先
let url = URL(string: "https://www.google.co.jp/")
//TTTAttributedLabelにリンクを指定
linkLabel.addLink(to: url, with: range)

実行するとこのような表示になります。


「URL」をタップすると以下のメソッドが呼ばれます。
func attributedLabel(_ label: TTTAttributedLabel!, didSelectLinkWith url: URL!) {
    print(url)//url => https://www.google.co.jp/
}

遷移するURLを画面に表示しないので色々使えると思います。

2017年1月28日土曜日

iOS SwiftでS3への画像アップロード

 こんにちは、Hiroです。今回はSwiftでAWSのS3へ画像をアップロードする方法について、ブログを書きたいと思います。
 AWS Cognitoでの認証が本来は望ましいのですが、今回は簡単にIAMユーザを作成し、ACCESS KEYとSECRET ACCESS KEYを利用した方法で紹介したいと思います。アプリをリリースする場合は、AWS Cognitoを利用するか、IAMユーザの場合は、アクセス権限を十分に絞ってください。


AWS上での事前準備


AWS上での準備については、省略しますが下記の2つを準備してください。IAMユーザについては、作成したS3のバケットへアップロード(PutObject)できる権限を付与しておく必要があります。
  • S3にバケットを作成
  • IAMユーザの作成(上記のバケットへの「s3:PutObject」権限あり)

CocoaPodsでAWS SDKをインストールをする


Podfileに下記を記載して、インストールします。
  use_frameworks!

  pod 'AWSS3'
$ pod install


認証の設定をする


冒頭で記載したとおり、今回はIAMユーザでの認証を行います。accessKeyとsecretKeyにはAWSで作成したIAMユーザのものを設定してください。
下記の処理は、S3で画像などをアップロードする前に1度だけ実行するようにします。
import AWSCore
...
...
    func configureService() {
        let credentialsProvider = AWSStaticCredentialsProvider(accessKey: "your access key", secretKey: "your secret key")
        let serviceConfiguration = AWSServiceConfiguration(region: AWSRegionType.apNortheast1, credentialsProvider: credentialsProvider)
        AWSServiceManager.default().defaultServiceConfiguration = serviceConfiguration
    }


UIImageを保存して、URLを取得する


S3へ投稿するファイルは、一時的に端末内に保存して、そのURLをS3のSDKに指定する必要があります。
下記のメソッドで、S3へのアップロードする画像が保存されているURLを取得できます。
    private func generateImageUrl(_ uploadImage: UIImage) -> URL {
        let imageURL = URL(fileURLWithPath: NSTemporaryDirectory().appendingFormat("upload.jpg"))
        if let jpegData = UIImageJPEGRepresentation(uploadImage, 80) {
            try! jpegData.write(to: imageURL, options: [.atomicWrite])
        }
        return imageURL
    }


S3へアップロードする


下記のメソッドでS3へアップロードができます。下記のメソッドを呼ぶ前には、上記で記載している認証の設定を事前に実行する必要があります。
また、「uploadRequest?.bucket」にはAWS上で作成したバケット名を指定し、「uploadRequest?.key」にはS3上に保存したいファイル名を指定します。 なお、ファイル名は「test/hello.jpg」とするとAWSコンソールなどから見た際にtestフォルダ内にhello.jpgファイルが保存されているように見えるので、ファイルをまとめて管理したい場合には、「test/」などのプレフィックスをつけるとよいでしょう。
import AWSS3
...
...
    public func uploadImage(_ uploadImage: UIImage) {
        let transferManager = AWSS3TransferManager.default()
        let uploadRequest = AWSS3TransferManagerUploadRequest()
        uploadRequest?.bucket = "your S3 bucket name"
        uploadRequest?.key = "your file name on S3"
        uploadRequest?.body = generateImageUrl(uploadImage)
        transferManager?.upload(uploadRequest).continue({ (task: AWSTask) -> Any? in
            if task.error != nil || task.exception != nil {
                // エラー
            }
            return nil
        })
    }


2017年1月27日金曜日

Swift3でDateからその月の月末のDateを取得

こんにちはonukiです。

今回はSwift3でDateの月末が何日か取得したかったので
備忘録がてら、私が行った方法を紹介したいと思います。

実装

var date = Date()
let calendar = NSCalendar(identifier: NSCalendar.Identifier.gregorian)!

// 年月日時分秒のNSComponents
var comp = calendar.components([.year, .month, .day, .hour, .minute, .second], from: date as Date)

// 月初の0時0分0秒に設定
comp.day = 1
comp.hour = 0
comp.minute = 0
comp.second = 0
// ここでcalendar.date(from: comp)!すれば月初のDateが取得できます

// その月が何日あるかを計算します
let range = calendar.range(of: .day, in: .month, for: date as Date)
let lastDay = range.length

// ここで月末の日に変えます
comp.day = lastDay

// Dateを作成
let retDate = calendar.date(from: comp)!

上記では現在日時からDateを作成し、その月の月末にしてるので
例えば2017年1月に実行した場合下記のフォーマットで整形しprintすると「20170131」になります。
let formatter = DateFormatter()
formatter.dateFormat = "yyyyMMdd"
let dateStr: String = formatter.string(from: retDate as Date)
print(dateStr)

2017年1月20日金曜日

Swift3でTTTAttributedLabelの文字列からリンク表示をやってみた

こんにちはonukiです。

今回はTTTAttributedLabelを使用し、
文字列からリンクを表示、リンクタップ制御を
Swiftでの実装方法を書いてこうと思います。

TTTAttributedLabelとは

リッチなテキストを表示するためのUILabelの機能を拡張するOSSです。
その機能の一つに文字列からリンクを検出してくれる機能があるので
今回は主にその部分の実装についてになります。

準備

インストールにはCocoaPodsを使用します。
pod 'TTTAttributedLabel'
それと、TTTAttributedLabelはObjective-Cで書かれているので
Bridging-Header.hにimportしてください。
#import <TTTAttributedLabel/TTTAttributedLabel.h>

実装

まずはTTTAttributedLabelをimportします
import TTTAttributedLabel
StoryboardにUILabelを適当に用意し
ClassにTTTAttributedLabelを指定してください。
それをIBOutlet接続します。
@IBOutlet weak var linkLabel: TTTAttributedLabel!
テキストのリンクをタップできるように設定します。
linkLabel.enabledTextCheckingTypes = NSTextCheckingResult.CheckingType.link.rawValue
リンクを含むテキストをセットします。
linkLabel.text = "URLにタップできます。\nhttps://www.google.co.jp/"
そうするとこのような表示になります。

このままだとタップが検知できないので
TTTAttributedLabelDelegateを設定します。
class ViewController: UIViewController, TTTAttributedLabelDelegate {
TTTAttributedLabelのDelegateを設定します。
linkLabel.delegate = self
テキスト内のリンクがタップされた場合、以下のメソッドが呼ばれます。
func attributedLabel(_ label: TTTAttributedLabel!, didSelectLinkWith url: URL!) {
    //処理
}
これで、文字列からリンクを表示、リンクタップ制御ができたと思います。

2016年12月31日土曜日

Swift filter, map, reduceメソッド

 こんにちは、Hiroです。久しぶりにiOSアプリをやることになり四苦八苦しています。
 さて、本日はRuby on Railsでは馴染み深いメソッドのSwift版を紹介したいと思います。


配列(Array)のfilter, map, reduce


配列に関して便利メソッドを3種類紹介します。先ずは、以下の例で操作対象となる配列を宣言しておきます。
// Array
var numbers: [Int] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

filter

クロージャで指定した条件を満たす、新しい配列を返却します。
例として、2の倍数を取得する処理を記述します。
let evenNumbers: [Int] = numbers.filter { (value: Int) -> Bool in
    return value % 2 == 0
}
print(evenNumbers)
// => [0, 2, 4, 6, 8]
上記のようにクロージャを渡すのですが、第一引数に「$0」でアクセスでき、下記のように簡略にすることもできます。
let evenNumbers: [Int] = numbers.filter { $0 % 2 == 0 }
print(evenNumbers)
// => [0, 2, 4, 6, 8]

map

配列の1つ1つにクロージャで指定した処理を行った配列の結果を返却します。
例として、1つ1つの要素を2倍にする処理を記述します。
let doubleNumbers: [Int] = numbers.map { (value: Int) -> Int in
    return value * 2
}
print(doubleNumbers)
// => [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
簡略式も下記に記載します。
let doubleNumbers: [Int] = numbers.map { $0 * 2 }
print(doubleNumbers)
// => [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

reduce

要素のたたみ込みをするためのメソッドです。要素をまとめて一つにする場合などで利用できます。 例として、要素の合計値を取得する処理を記述します。
let totalNumber = numbers.reduce(0) { (total: Int, value: Int) -> Int in
    total + value
}
print(totalNumber)
// => 45
簡略式も下記に記載します。
let totalNumber = numbers.reduce(0) { $0 + $1 }
print(totalNumber)
// => 45


辞書(Dictionary)のfilter, map, reduce


辞書に関しても上記の「filter」「map」「reduce」のメソッドは使えますので、簡略式ですが、こちらも記載しておきます。先ずは、例で操作対象となる辞書を宣言しておきます。
// Dictionary
var dictNumbers = ["zero":0, "one": 1, "two": 2, "three": 3 , "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9]

filter

Dictionaryのため、順序保証がないのと、返却値はタプルの配列になっています。
let evenDictNumbers = dictNumbers.filter { $0.1 % 2 == 0 }
print(evenDictNumbers)
// => [("four", 4), ("zero", 0), ("two", 2)] 

map

こちらもタプルとしていますが、辞書で返却したい場合が普通のケースですので、そん場合、次で紹介する「reduce」のやり方がよいでしょう。
let doubleTupleNumbers = dictNumbers.map { ($0.0, $0.1 * 2) }
print(doubleTupleNumbers)
// => [("three", 6), ("one", 2), ("nine", 18), ("seven", 14), ("four", 8), ("five", 10), ("zero", 0), ("six", 12), ("eight", 16), ("two", 4)]

reduce

let doubleDictNumbers = dictNumbers.reduce([String: Int]()) { var varDict = $0; varDict[$1.0] = $1.1 * 2; return varDict}
print(doubleDictNumbers)
// => ["three": 6, "one": 2, "nine": 18, "seven": 14, "four": 8, "five": 10, "zero": 0, "six": 12, "eight": 16, "two": 4]
上記で、注意点としては、一度「$0」を「varDict」変数に代入しているところです。これは、「$0」がイミュータブルな変数だからです。
そのため、下記ではエラーとなります。
let doubleDictNumbers = dictNumbers.reduce([String: Int]()) { $0[$1.0] = $1.1 * 2; return $0}
// =>Cannot assign through subscript: '$0' is immutable


いかがでしたでしょうか。Ruby on Railsではおなじみのメソッドですが、少しSwiftならではの制約があります。ただ、とても可読性が高く、便利なメソッドなのでどんどん利用してみようと思います。

2016年12月30日金曜日

ObjectMapperでJSONのネスト配列に対応する方法

こんにちは、onukiです。

私はSwiftでJSONを取り扱う際に、
ObjectMapperを使用してるのですが
今回は読み込むJSONにネスト配列がある場合の使い方を書いていこうと思います。

ObjectMapperとは

ObjectMapperとはJSONデータをモデルに変換する処理を
簡単に扱えるライブラリです。

使い方

今回、読み込むJSONは以下のようなネスト配列が含まれているものを使用します。
{
    "id": 1,
    "name": "user1",
    "address": "hoge",
    "photos": [
    {
    "id": 1,
    "name": "photo1"
    },
    {
    "id": 2,
    "name": "photo2"
    }
    ]
}

ObjectMapperはMappableプロトコルをモデルクラスに実装し使用するのですが
今回はネスト配列に対応するために2つ作成します。
struct User: Mappable {
    var id = 0
    var name = ""
    var address = ""
    var photos: [Photo] = []
    
    init?(map: Map){}
    mutating func mapping(map: Map) {
        id <- map["id"]
        name <- map["name"]
        address <- map["address"]
        photos <- map["photos"]
    }
}
struct Photo: Mappable {
    var id = 0
    var name = ""
    
    init?(map: Map){}
    mutating func mapping(map: Map) {
        id <- map["id"]
        name <- map["name"]
    }
}

JSONからモデルに変換するのには以下のように取得します。
let user: User = Mapper().map(JSONString: jsonString)!
print(user.name) // => "user1"

そして、userのphotos配列から0番目のデータを取得したい際にはこのように取得します。
let photo: Photo = user.photos[0]

これでObjectMapperでJSONのネスト配列を読み込み、扱うことが出来ました。

2016年12月22日木曜日

Swift 型推論とコンパイル時間

 こんにちは、Hiroです。今回はサクッとブログを書きます。

型推論とは


Swiftは静的型付け言語ですので、初めて聞くと「?」となると思いますが、Swiftでは、変数の宣言時に型を明示しなくとも代入されている値から、「コンパイル時」に型を推測してくれる機能があります。
そのため、下記の変数value1、value2はどちらの宣言であっても、Int型として問題なく動作します。
var value1: Int = 10
var value2 = 10
print("value1: \(value1), value2: \(value2)")
// => value1: 10, value2: 10


型推論の注意点


このように、どちらでも問題ないのであれば、型推論だけでいいじゃないかと思いますが、上記で記載しているとおり、「コンパイル時」に型を推測するため、あまりにも型推論が多いとコンパイルに時間がかかってきてしまいます。小規模なアプリでは、問題ないのですが、大規模なコードになるとコンパイルに時間がとられてしまい、開発効率を落としかねないので、注意したいところですね。

このように、簡易的に使えるものであっても、理解をした上で利用することが大切だと思いました。

2016年12月16日金曜日

Alamofireのバージョン4以降でCookie付きの通信を行う

こんにちは、onukiです。

今回はAlamofireでCookie付きの通信を行う方法です。
Alamofireのバージョン4以降だと簡単にできるのでサクッと紹介します。

Alamofireのrequestメソッドにheadersが渡せるようになったので、
そこにCookie情報を渡せばそれだけでOKです。
例えば、headersは[String: String]形式なので、
["Cookie": "hoge"]の様な形で渡す感じです。
let cookie: [String: String] = ["Cookie": "hoge"]
Alamofire.request("https://~",
    method: .get,
    parameters: nil,
    encoding: JSONEncoding.default,
    headers: cookie).responseJSON {
        //処理
}

2016年12月7日水曜日

Swift3でMapKitの吹き出し(Callout)タップを取得したい!

こんにちは、onukiです。

今回、iOSのMapKitで吹き出しのタップを取得しようと思ったのですが、
これが案外簡単にいかなかったというか無理矢理やりました。(笑)

MKMapViewDelegateに以下のメソッドが用意されています
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
    //処理
}
ただ、こいつは基本的にMKAnnotationViewの
「leftCalloutAccessoryView」か「rightCalloutAccessoryView」にUIButton等のUIControlが取得できるものを配置し、
そして、そのボタンを押すなどした時に、このメソッドが呼ばれます。
しかし、今回やりたいことはGoogleMapみたいに吹き出しのどこでもタップできるようにしたいという事。
(というか吹き出しにボタンを配置したくない。。。)

というわけで結論を早々に述べるとMKAnnotationViewに直接UITapGestureRecognizerを設定します。
MapKitはピンを刺すときにMKAnnotationViewを使用していますがピン部分だけではなく
吹き出し(Callout)部分もSubViewではなくピンと一緒にMKAnnotationViewとして扱われています。
なので以下のようにすると吹き出し部分のタップも取得できます。
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(hoge.tapGesture(gestureRecognizer:)))
    view.addGestureRecognizer(tapGesture)
}
これで吹き出し部分のタップが取得できます!

ですが、このままだとピン画像(MKAnnotationView.image)の部分もタップできてしまうので、
タップ処理側で以下のような条件を付けます。
func tapGesture(gestureRecognizer: UITapGestureRecognizer){
    let view = gestureRecognizer.view
    let tapPoint = gestureRecognizer.location(in: view)
    //ピン部分のタップだったらリターン
    if tapPoint.x >= 0 && tapPoint.y >= 0 {
        return
    }
    //処理
}

なぜこれでいけるかというと、MKAnnotationView自体のフレームはピン画像部分のみで
吹き出し部分はMKAnnotationViewのフレーム外に描画されています。

以上、だいぶ無理矢理タップ判定しましたが
これでGoogleMapと同じく吹き出しのどこをタップされても取得することができます。
(もっとスマートなやり方ご存知の方、ご教授いただけると幸いです)

2016年11月24日木曜日

Swift3で消えたadvancedBy

Swift2で部分文字列を取得するのにadvancedByを使用してindexを取得していたのが
Swift3では以下の方式に変更されました。

Swift2
str.startIndex.advancedBy(2)
これが
Swift3
str.index(str.startIndex, offsetBy: 2)
のような形になります。

2016年10月31日月曜日

Macでバックスラッシュ入力する

Swiftの文字列内で変数(定数)を展開する場合、\(バックスラッシュ)を使います。

let name = "John"
print("Hello \(name)") // "Hello John\n"

Macのキーボード設定だとデフォルトでは、「\」を入力するのに「Option(alt)キー + ¥」となっています。
ただ、普段コーディングをしているときは、「¥」より「\」を入力する機会のが多いですよね。なので、私は設定を変更しています。

キーボードの設定は、[システム環境設定]-[キーボード]-[入力ソース]より変更できますので、皆さんも参考にしてみてください。