- 投稿日:2020-10-10T23:33:23+09:00
swiftで文字列を1文字ずつの配列に変換する
AtCoderの問題を解いている際に、文字列を1文字ずつ分割する必要があったのでメモ
let charArray = Array("abcdef") print(charArray) // ["a", "b", "c", "d", "e", "f"] print(type(of: charArray[0])) // Character
- 投稿日:2020-10-10T11:56:37+09:00
SwiftでUUIDをbase64にして短縮する。
UUIDは分散的に生成できて、かなり使いやすいのですがエンコードする時にいかんせん長いです。
E2731BE6-470D-4782-B853-E5B13E8A1ECF
D879A224-9A58-4D71-8E43-B7F3D001B7E4
FFF4DCE4-3C49-459B-BDB9-EB4B5A030FEB
これをそのまま保存するのは流石に避けたい。
UUIDは通常16進法で書かれるので、文字列で保存するならもっと短縮できるはずです。
実装
こんな
extension
を実装します。extension UUID { public var base64String: String { var base64WithPadding = self.data.base64EncodedString() // base64の末尾の==を取り除く base64WithPadding.removeLast(2) return base64WithPadding } public var data: Data { var result = Data() let uuidTuple = self.uuid result.append(uuidTuple.0) result.append(uuidTuple.1) result.append(uuidTuple.2) result.append(uuidTuple.3) result.append(uuidTuple.4) result.append(uuidTuple.5) result.append(uuidTuple.6) result.append(uuidTuple.7) result.append(uuidTuple.8) result.append(uuidTuple.9) result.append(uuidTuple.10) result.append(uuidTuple.11) result.append(uuidTuple.12) result.append(uuidTuple.13) result.append(uuidTuple.14) result.append(uuidTuple.15) return result } }これで36文字が22文字まで短縮できます。
40CC21EA-7D27-49CC-8A18-280373933BE2 -> QMwh6n0nScyKGCgDc5M74g 2AF87112-E64C-441F-85E1-FD4FCCD097CA -> KvhxEuZMRB+F4f1PzNCXyg D9C051E6-D7E2-4198-9CB1-A399E347D860 -> 2cBR5tfiQZicsaOZ40fYYAテスト
以下のコードでテスト
for _ in 0..<10 { let id = UUID() let data = Data(base64Encoded: id.base64String + "==")! let uuid = UUID(uuid: ( data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15] )) print(id, "->", id.base64String, "->", uuid) }40CC21EA-7D27-49CC-8A18-280373933BE2 -> QMwh6n0nScyKGCgDc5M74g -> 40CC21EA-7D27-49CC-8A18-280373933BE2 2AF87112-E64C-441F-85E1-FD4FCCD097CA -> KvhxEuZMRB+F4f1PzNCXyg -> 2AF87112-E64C-441F-85E1-FD4FCCD097CA D9C051E6-D7E2-4198-9CB1-A399E347D860 -> 2cBR5tfiQZicsaOZ40fYYA -> D9C051E6-D7E2-4198-9CB1-A399E347D860可逆圧縮できている。
- 投稿日:2020-10-10T11:36:08+09:00
どこよりも丁寧なGoogle Maps SDK for iOSの使い方
「Mapを表示するぞ!!」
…と、何だかんだiOSアプリを本格的に作成していくためのスタートラインとして、まずはAPIの使い方を学習していきました。
Maps SDK for iOSのチュートリアルは多く存在しますが、右も左も分からない初心者にはあまり丁寧な記事が見つからなかったので、作成がてらアウトプットも兼ねて順を追って紹介していきます。
※開発環境
Xcode 12
Swift 5.3APIって?
APIとはApplication Programming Interface(アプリケーション・プログラミング・インターフェイス)略称です。
APIとは、あるコンピュータプログラム(ソフトウェア)の機能や管理するデータなどを、外部の他のプログラムから呼び出して利用するための手順やデータ形式などを定めた規約のこと。
(なるほど、分からん…!)
概要を端的にすると、ソフトウェア同士のやりとりの橋渡しの機能がAPIとなります。
GoogleやTwitterなど、多くの会社はAPIを提供しています。その使いたい対象の機能(サービス)を他のプログラムから呼び出してもらうための命令や関数のことをAPIといいます。Google Mapを使えるように設定
GoogleのMap API(iOS)を使いたいので、設定を行います。
Google Maps Platformに飛び
画面右上のConsoleに移動します。「プロジェクトの選択」をクリックし、新しいプロジェクトを作成します。
プロジェクト名を入力後、作成ボタンを押します。
プロジェクトが開くと思うので、APIからMaps SDK for iOSを選択
※ホームに遷移していた場合
APIとサービス → ダッシューボードを選択
APIとサービスの有効化をクリック
APIライブラリの画面が出てきますので、Maps SDK for iOSを選択してください。
有効にするをクリックします。
管理画面が出てきますので、認証情報からに「認証情報を作成」を押して「APIキー」を選択します。
これでAPIキーが作成されました。
しかし、まだ設定は終わっていません。キーに制限がないとの注意が出ますので、制限を有効していきます。対象となるAPIキーを選択して設定していきます。APIキーの制限と名前変更から今回使用したいMaps SDK for iOSを選択チェックして保存します。
これでGoogle MapsのAPIを使用する設定が終わりました。
APIKeyを使う
Xcodeからプロジェクトを作成し、Podfileに以下を記載しpod installします。
Podfiletarget 'プロジェクト名' do # Comment the next line if you don't want to use dynamic frameworks use_frameworks! source 'https://github.com/CocoaPods/Specs.git' #追加 pod 'GoogleMaps' #追加 pod 'GooglePlaces' #追加 # Pods for プロジェクト名 end次にAppDelegateにAPIKeyを設定していきます。
AppDelegate.swiftを開いて、import GoogleMaps
を追加します。※1
didFinishLaunchingWithOptions
のメソッド部分に以下を追記します。
※1はアプリ起動後にAppDelegateのdidFinishLaunchingWithOptionsが呼ばれ、この部分で全体的な機能の初期化処理を行います。AppDelegate.swiftfunc application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. #発行したAPIキーを設定 GMSServices.provideAPIKey("発行したAPIキーをここに記載") return true }次に
Info.plist
に移動し、Information Property List
にArrayにgooglechromes
とcomgooglemaps
を追加しましょう。
ViewController.swiftを開きimportを追加しましょう。
import GoogleMaps
import CoreLocation
viewDidLoadの中に以下のコードを書いていきます。
ViewController.swiftoverride func viewDidLoad() { super.viewDidLoad() #表示するマップの座標位置と表示されるサイズを生成 let camera = GMSCameraPosition.camera(withLatitude: 34.6862, longitude: 135.5196, zoom: 6.0) let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera) mapView.isMyLocationEnabled = true #現在地情報を有効にする view = mapView #UIViewのインスタンス #指定箇所にピンを立てる let marker = GMSMarker() marker.position = CLLocationCoordinate2D(latitude: 34.6862, longitude: 135.5196)#緯度、軽度を設定 marker.title = "Osaka" marker.snippet = "Japan" marker.map = mapView }起動
ビルド&ランをしましょう。
実行後、選択したロケーションにピンが立っているかと思います。以上、Google Maps APIの使い方でした。
- 投稿日:2020-10-10T10:24:26+09:00
'com.apple.developer.nfc.readersession.formats' because 'NDEF is disasllowed'.と怒られたときのトリセツ
はじめに
CoreNFCを使って個人開発をしています!
今回はアプリをAppStoreに載せるためにValidateするのですが、そこでエラーになり怒られたので、そのトリセツです!!
エラー対処のトリセツ
.entitlementファイルを開く
Removeと書かれているItemを削除
※引用画像 : StackoverFlowそうしましたら、もう一度Validateしてみましよう!
最後に
トリセツを最後まで読んでいただき、ありがとうございました!
CoreNFCを使ってどんなアプリを開発しているか、ぜひGithubに見に来てください!!Github : https://github.com/Ryosukekamimura
- 投稿日:2020-10-10T07:40:02+09:00
個人的に必須なUIColorのextension
先にコードだけ載せておきます
//宣言 extension UIColor { class func rgba(r: Int, g: Int, b: Int, alpha: CGFloat) -> UIColor{ return UIColor(red: CGFloat(r) / 255.0, green: CGFloat(g) / 255.0, blue: CGFloat(b) / 255.0, alpha: alpha) } }//呼び出し let white: UIColor = .rgba(r: 251, g: 250, b: 245, alpha: 1)UIcolorのデフォルトのイニシャライザは0〜1の値でしか指定できないので扱いづらいですよね。
他にもオススメのextensionがあればぜひコメントで教えてください!
- 投稿日:2020-10-10T06:01:17+09:00
iOS 14 アプリケーションのWidgetの追加(通常のWidget、Intentsを使用した構成可能なWidget)
本記事では以下の内容を説明します。
- 既存のアプリケーションへのウィジェットの追加
- ⭐️ ユーザーがコンテンツを構成できる (都市の選択など) ウィジェットの追加
既存のアプリケーションへのウィジェットの追加
アプリケーションターゲットの作成
既存の iOS アプリケーションへのウィジェットの追加は簡単です。ターゲット
Widget Extension
を追加してください。さて、
Include Configuration Intent
というボックスを選択していることを確認してください。この記事のパート2では、その構成ファイルが必要になるためです。データ構造
これで
WidgetExample-Widget
という新しいフォルダーが表示されます。クリックしてファイルWidgetExample_Widget.swift
を開き、そのファイルのコンテンツを削除して、このガイドに従います。ウィジェットに表示したいデータのデータ構造を作成できます。この例では、猫の情報を表示します!
struct CatEntry: TimelineEntry { var date: Date var name: String var lastFed: Date var lastPlayedWith: Date }
IntentTimelineProvider
構造の作成
IntentTimelineProvider
構造は、次の3種類のコンテンツを提供します:
1>placeholder
(プレースホルダー)は、ウィジェットがロードされているときに表示されます。
2>getSnapshot
は、ウィジェットギャラリーに表示されます。
3>getTimeline
は、実際のウィジェット表示に使用されます。まず、タイプ
IntentTimelineProvider
に確認するプログラム構造体を作成し、次にEntry
のタイプを定義します。struct CatProviderStatic: TimelineProvider { typealias Entry = CatEntry func getSnapshot(in context: Context, completion: @escaping (CatEntry) -> Void) { //TODO } func getTimeline(in context: Context, completion: @escaping (Timeline<CatEntry>) -> Void) { //TODO } func placeholder(in context: Context) -> CatEntry { //TODO } }
getSnapshot
機能については、あなたのウィジェットが何の情報を提供するかをユーザーが理解できるよう、ウィジェットビューに例の値を提供することができます:func getSnapshot(in context: Context, completion: @escaping (CatEntry) -> Void) { let entry = CatEntry(date: Date(), name: "猫の名前", lastFed: Date(), lastPlayedWith: Date()) completion(entry) }プレースホルダービューについては、以下のように空の値または例の値を表示できます:
func placeholder(in context: Context) -> CatEntry { return CatEntry(date: Date(), name: "猫の名前", lastFed: Date(), lastPlayedWith: Date()) }そして、タイムライン表示については、表示する実際のコンテンツを提供できます。
この例では、ただ静的データ値を表示します。あなたのアプリケーションで、
Core Data
(そのデータを共有する方法についての記事はこちら)、またはオンラインから、CloudKit
から、またはUserDefaults
からのコンテンツをフェッチできます。func getTimeline(in context: Context, completion: @escaping (Timeline<CatEntry>) -> Void) { let entry = CatEntry(date: Date(), name: "ネコノヒー", lastFed: Date(), lastPlayedWith: Date()) let timeline = Timeline(entries: [entry], policy: .atEnd) completion(timeline) }ウィジェットビューのデザイン
ウィジェットの SwiftUI ビューをデザインできるようになりました。
struct CatWidgetView: View { @Environment(\.widgetFamily) var family var entry: CatEntry var body: some View { VStack { if family == .systemMedium || family == .systemLarge { Image("kitty") .resizable() .frame(width: 50, height: 50) .padding(.vertical, 5) } Text(entry.name) .font(.headline) .padding(1) Text("最後に遊んだ時間 " + entry.lastPlayedWith.getString()) .font(.caption) .padding(.horizontal) Text("最後に餌をあげた時間 " + entry.lastFed.getString()) .font(.caption) .padding(.horizontal) } } }ウィジェットのサイズを確認するには
@Environment(\.widgetFamily) var family
変数を使用できます。この例では、ウィジェットのサイズが画像の表示に十分な大きさである場合の猫の画像を表示しています。
if family == .systemMedium || family == .systemLarge { Image("kitty") .resizable() .frame(width: 50, height: 50) .padding(.vertical, 5) }ウィジェットアプリケーションをコーディングします
これで、ウィジェットアプリケーションをコーディングできるようになりました。
@main struct CatWidget: Widget { var body: some WidgetConfiguration { IntentConfiguration(kind: "CatWidget", intent: ConfigurationIntent.self, provider: CatProvider()) { entry in CatWidgetView(entry: entry) }.configurationDisplayName("猫") .description("いつ猫に餌をあげたり遊んだりしたか見てみましょう。") } }これで、シミュレーターでアプリを実行して、設計したばかりのウィジェットを画面に追加できるようになりました。
ユーザーがウィジェットを構成できるようにします
お天気ウィジェットを使ったことがあれば、ウィジェットを長押しして構成することにより、表示される都市をユーザーが選択できることをご存じでしょう。
Intents
フレームワークとTargetを使用して、この機能を追加することができます。
Intents
プログラムターゲットの追加この段階では UI 要素は不要なため、オプション
Include UI Extension
のチェックは外して結構です。作成された Intents ターゲットページで、
Supported Intents
という名前のセクションを見つけます。ConfigurationIntent
という名前のアイテムを新規作成します。名前は[インテント名]Intent
とします。インテント名は左側の.intentdefinition
ファイル内に表示されます。
.intentdefinition
の構成次に、以前に作成したウィジェット内の
WidgetExample_Widget.intentdefinition
ファイルにつき、新しく作成されたIntents
拡張機能をインテントのターゲットとして追加します。画面左側の
Configuration
をクリックします。右側で、以下の画像と構成が同じであることを確認してください。
次に、
cat
という名の新しいパラメータを追加します。新たに作成された
cat
パラメータの設定画面で、猫の識別子を入力として使用するため、タイプType
にString
を選択します。
IntentHandler
の構成次に、
IntentHandler.swift
ファイルを開きます。このファイルでは、ユーザーがウィジェットの構成を行うオプションを提供します。この例では、オプションは猫の識別子となります。クラスの
INExtension
タイプの隣にConfigurationIntentHandling
キーワードを追加すると、Xcode ソフトウェアが自動で次に追加すべき関数の名前を表示してくれます。class IntentHandler: INExtension, ConfigurationIntentHandling { ... }この例では、完成した
IntentHandler.swift
ファイルは以下のとおりとなります。class IntentHandler: INExtension, ConfigurationIntentHandling { func provideCatOptionsCollection(for intent: ConfigurationIntent, searchTerm: String?, with completion: @escaping (INObjectCollection<NSString>?, Error?) -> Void) { let catIdentifiers: [NSString] = [ "ネコノヒー", "ムギ", "アズキ" ] let allCatIdentifiers = INObjectCollection(items: catIdentifiers) completion(allCatIdentifiers, nil) } override func handler(for intent: INIntent) -> Any { // This is the default implementation. If you want different objects to handle different intents, // you can override this and return the handler you want for that particular intent. return self } }関数
provideCatOptionsCollection
では、値のリストを入力する必要があります。これらの値は、実際にはUser Defaults
、Core Data
、オンラインのいずれかからフェッチできます。この例では値がハードコーディングされています。「App Extensions」で「Core Data」を使用する
IntentTimelineProvider
を作成本記事のパート1では、
TimelineProvider
を使用しました。今回は、IntentTimelineProvider
を使用します。
IntentTimelineProvider
とTimelineProvider
の間のデータ構造はほぼ同一です。追加のtypealias
を宣言する必要がある点が違いとなります。typealias Intent = ConfigurationIntentもう1つの違いは、次のとおりです。各関数で、インテントの選択を表す追加のパラメーター
ConfigurationIntent
を取得します。struct CatProvider: IntentTimelineProvider { typealias Intent = ConfigurationIntent typealias Entry = CatEntry func placeholder(in context: Context) -> CatEntry { let entry = CatEntry(date: Date(), name: "", lastFed: Date(), lastPlayedWith: Date()) return entry } func getSnapshot(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (CatEntry) -> Void) { let entry = CatEntry(date: Date(), name: "猫の名前", lastFed: Date(), lastPlayedWith: Date()) completion(entry) } func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline<CatEntry>) -> Void) { let entry = CatEntry(date: Date(), name: configuration.cat ?? "", lastFed: Date(), lastPlayedWith: Date()) let timeline = Timeline(entries: [entry], policy: .atEnd) completion(timeline) } }
configuration.cat
プロパティを使用して、ユーザーが選択したオプションの値を読み取ることができます。let entry = CatEntry(date: Date(), name: configuration.cat ?? "", lastFed: Date(), lastPlayedWith: Date())
CatWidget
のコードを更新します。パート1では
StaticConfiguration
を使用しましたが、このパートではIntentConfiguration
(Supported Intents
で設定した名前)を使用します。@main struct CatWidget: Widget { var body: some WidgetConfiguration { IntentConfiguration(kind: "CatWidget", intent: ConfigurationIntent.self, provider: CatProvider()) { entry in CatWidgetView(entry: entry) }.configurationDisplayName("猫") .description("いつ猫に餌をあげたり遊んだりしたか見てみましょう。") } }シミュレーターでプログラムを実行できるようになりました。ウィジェットを長押しすると
Edge Widget
というオプションが表示され、猫の名前を変更できます。⭐️