20190828のSwiftに関する記事は6件です。

【Xcode】No such module と表示された時の対処

結論

ターゲットを増やしたが、Podfileのターゲットを増やしていなかったため
Podfileのターゲットを増やし、再度 pod install で解消された

普段触らなすぎて、忘れていました。。。

環境

Xcode: 10.1
Swift: 4.2
pod: 1.7.1

手順

Podfileにターゲットを追加

platform :ios, '9.0'
use_frameworks!

def install_pods
 pod 'Firebase/Core'
 pod ....
end

target 'すでに存在してるターゲット名' do
 install_pods
end

# 新しいターゲットを追記し忘れていた
target '新しく追加したターゲット名' do
 install_pods
end

インストール実施

pod install

振り返り

こんなことで3時間ほど費やしてしまった コンチクショー!(振り返ってない)

参考に試したが自分の場合ダメだったこと

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Swift 5]UIButtonに設定したimage(画像)を右側に表示する

UIButtonは、アイコンと文字を同時に設定できますが、デフォルトでは左側に表示されます。
文字を左、アイコンを右側に表示したかったのですが、思ったより単純にはできず、今回以下のように実装しました。

実装

UIButton+.swift
extension UIButton {
    // ボタンのアイコンをLeading(右側)に表示する
    func iconToRight() {
        if #available(iOS 11.0, *) {
            // leadingはiOS 11以降のため
            contentHorizontalAlignment = .leading
        } else {
            contentHorizontalAlignment = .right
        }
        semanticContentAttribute =
            UIApplication.shared.userInterfaceLayoutDirection == .rightToLeft
            ? .forceLeftToRight : .forceRightToLeft
    }
}

使用方法

sampleButton.iconToRight()

もう一つ、トランスフォームを使って反転させる方法もあるようでしたが、今回はsemanticContentAttributeを使う方法を採用しました。

代替方法

button.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
button.titleLabel?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
button.imageView?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)

参考

https://stackoverflow.com/questions/7100976/how-do-i-put-the-image-on-the-right-side-of-the-text-in-a-uibutton

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Macアプリ初心者:NSTableView でカスタムした一覧を作ってみる

今回は前回作成したプロジェクトを元にしてカスタム Cell を作成して見た目を変えていきます。
株価一覧を表示するイメージのサンプルアプリを作ってみます。

完成イメージ

こんな感じのシンプルなものです。
スクリーンショット 2019-08-28 9.22.05.png

環境

  • macOS Mojave:10.14.6
  • Xcode:10.3

カスタムセルの作成

今回は StoryBoard を利用してカスタムセルを作成しました。
個人的には大きいプロジェクトでは XIB を利用して個々のパーツに分解して作った方がメンテしやすいと思います。

カスタムセルのイメージ

株価のステータス表示用の ImageView が左側に配置されていて、右側に企業名と株価を表示する TextField を配置するシンプルな構成です。
スクリーンショット 2019-08-28 9.35.15.png

StoryBoard でアイテムを配置

スクリーンショット 2019-08-28 9.38.37.png

TableView の見え方を変更

表示するだけのViewのため、Clickした時に選択できないようにし(Highlight:None)、見やすいように縞模様表記にし(Alternating Rows:チェック)、水平のグリッド線を表示(Horizontal Grid:Solid)します。
ファイル名

カスタムセルクラスを作成

それぞれのアイテムを持っているだけの単純なクラスです。

CustomNSTableCellView.swift
import Cocoa

class CustomNSTableCellView: NSTableCellView {

    @IBOutlet weak var stockImage: NSImageView!
    @IBOutlet weak var companyName: NSTextField!
    @IBOutlet weak var stockPrice: NSTextField!

}

StoryBoard とカスタムセルクラスを紐づける

Kobito.SX5sr9.png

ソースコード:カスタムセルクラスの利用

下準備としてセルの高さと表示するアイテムデータを作成

ViewController.swift
    @IBOutlet weak var tableView: NSTableView! {
        didSet {
            self.tableView.dataSource = self
            self.tableView.delegate = self

            self.tableView.rowHeight = 88
        }
    }

    // MARK: - private variables
    private var values = [
        ["name" : "○○株式会社", "price": 1000, "status": "up"]
        ,["name" : "○×水産", "price": 12345, "status": "down"]
        ,["name" : "株式会社□○", "price": 345, "status": "flat"]
        ,["name" : "×△ホールディングス", "price": 321, "status": "up"]
        ,["name" : "ABC BANK", "price": 20, "status": "down"]
        ,["name" : "▼○重工", "price": 98000, "status": "up"]
    ]

状態によってテキストやイメージ画像を差し替える

CustomNSTableCellView.swift
    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
        let result = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "MyView"), owner: self) as? CustomNSTableCellView

        // Set the stringValue of the cell's text field to the nameArray value at row
        switch self.values[row]["status"] as! String {
        case "up":
            result?.stockImage.image = NSImage(named: NSImage.Name("up"))
            result?.stockImage.contentTintColor = NSColor.red
            result?.companyName.textColor = NSColor.red
        case "down":
            result?.stockImage.image = NSImage(named: NSImage.Name("down"))
            result?.stockImage.contentTintColor = NSColor.green
            result?.companyName.textColor = NSColor.green
        case "flat":
            result?.stockImage.image = NSImage(named: NSImage.Name("flat"))
            result?.stockImage.contentTintColor = NSColor.gray
            result?.companyName.textColor = NSColor.gray
        default:
            break
        }
        result?.companyName.stringValue = self.values[row]["name"] as! String
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        let commaString = formatter.string(from: self.values[row]["price"] as! NSNumber)
        result?.stockPrice.stringValue = commaString ?? "-"

        // Return the result
        return result
    }

全ソースコード(ViewController)
ViewController.swift
import Cocoa

class ViewController: NSViewController {

    // MARK: - IBOutlet
    @IBOutlet weak var tableView: NSTableView! {
        didSet {
            self.tableView.dataSource = self
            self.tableView.delegate = self

            self.tableView.rowHeight = 88
        }
    }

    // MARK: - private variables
    private var values = [
        ["name" : "○○株式会社", "price": 1000, "status": "up"]
        ,["name" : "○×水産", "price": 12345, "status": "down"]
        ,["name" : "株式会社□○", "price": 345, "status": "flat"]
        ,["name" : "×△ホールディングス", "price": 321, "status": "up"]
        ,["name" : "ABC BANK", "price": 20, "status": "down"]
        ,["name" : "▼○重工", "price": 98000, "status": "up"]
    ]


    // MARK: - override func
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }
}

extension ViewController: NSTableViewDataSource, NSTableViewDelegate {

    // MARK: - NSTableViewDataSource
    func numberOfRows(in tableView: NSTableView) -> Int {
        return self.values.count
    }

    // MARK: - NSTableViewDelegate
    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
        let result = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "MyView"), owner: self) as? CustomNSTableCellView

        // Set the stringValue of the cell's text field to the nameArray value at row
        switch self.values[row]["status"] as! String {
        case "up":
            result?.stockImage.image = NSImage(named: NSImage.Name("up"))
            result?.stockImage.contentTintColor = NSColor.red
            result?.companyName.textColor = NSColor.red
        case "down":
            result?.stockImage.image = NSImage(named: NSImage.Name("down"))
            result?.stockImage.contentTintColor = NSColor.green
            result?.companyName.textColor = NSColor.green
        case "flat":
            result?.stockImage.image = NSImage(named: NSImage.Name("flat"))
            result?.stockImage.contentTintColor = NSColor.gray
            result?.companyName.textColor = NSColor.gray
        default:
            break
        }
        result?.companyName.stringValue = self.values[row]["name"] as! String
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        let commaString = formatter.string(from: self.values[row]["price"] as! NSNumber)
        result?.stockPrice.stringValue = commaString ?? "-"

        // Return the result
        return result
    }
}

よかったら いいね してください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

'could not dequeue a view of kind: UICollectionElementKindCell with identifier hogeCell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'[Swift]

概要

CollectionViewを使ったViewControllerに遷移しようとしたら

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'could not dequeue a view of kind: UICollectionElementKindCell with identifier recipesCell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'

対策

参考

Xcode - TableViewを表示できない|teratail

segueで別のやつ

VCから引っ張るんじゃなくてUIから引っ張るとめんどいことになるから気をつけて
segueはVC間で繋いで
idだけ指定して
遷移させたいタイミングでperformSegueを書けばいい(この時idを指定する)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AppDelegateについて

目的

iOSアプリを開発する上で、当たり前のように使うAppDelegateクラスについての理解を深める。また、ストーリーボードを使用しない場合のAppDelegateへの記述にも触れる。

ソースコード

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

  var window: UIWindow?

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    self.window = UIWindow(frame: UIScreen.main.bounds)
    self.window?.rootViewController = UINavigationController(rootViewController: <表示したいViewControllerを入れる>) 
    self.window?.makeKeyAndVisible()

    return true
  }
  func applicationWillResignActive(application: UIApplication) {
        println("アプリ閉じそうな時に呼ばれる")
    }

    func applicationDidEnterBackground(application: UIApplication) {
        println("アプリを閉じた時に呼ばれる")
    }

    func applicationWillEnterForeground(application: UIApplication) {
        println("アプリを開きそうな時に呼ばれる")
    }

    func applicationDidBecomeActive(application: UIApplication) {
        println("アプリを開いた時に呼ばれる")
    }

    func applicationWillTerminate(application: UIApplication) {
        println("フリックしてアプリを終了させた時に呼ばれる")
    }
}

@UIApplicationMainとは

#import
#import "AppDelegate.h"

int main(int argc, char *argv[]) {
  @autoreleasepool {
  //AppDelegateのクラス名を指定
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
  }
}

@UIApplicationとは上記のコードを省略するための記述であり、この記述のおかげで上記のmain関数を自動実装してくれます。ちなみにこのmain関数というのはアプリケーションを起動した時点で、はじめに実行する関数であり、ここでAppDelegateのクラス名を指定しているため、アプリ起動時などにAppDelegateが実行されるようになっている。

AppDelegate.swiftとは

xcodeでプロジェクトをcreateした時点で自動生成されるファイルの一つであり、アプリ全体のライフタイムイベントを管理するためにAppDelegateクラスが記述されている。
そしてそのAppDelegateクラスはUIResponderを継承して、UIApplicationDelegateプロトコルを適合している。

//上記省略

func applicationWillResignActive(application: UIApplication) {
        println("アプリ閉じそうな時に呼ばれる")
    }

    func applicationDidEnterBackground(application: UIApplication) {
        println("アプリを閉じた時に呼ばれる")
    }

    func applicationWillEnterForeground(application: UIApplication) {
        println("アプリを開きそうな時に呼ばれる")
    }

    func applicationDidBecomeActive(application: UIApplication) {
        println("アプリを開いた時に呼ばれる")
    }

    func applicationWillTerminate(application: UIApplication) {
        println("フリックしてアプリを終了させた時に呼ばれる")
    }

上記のようにAppDelegateクラスにはいくつかのメソッドがファイル生成時に定義されており、何かしらの動作がアプリに行われた際に各メソッドが実行されるようになっている。

UIResponderクラスとは

UIResponder(のインスタンス)は、UIKitアプリのイベント処理バックボーン(裏側の処理)を構成しています。つまりUIResponderクラスはイベントの処理を管理するクラスであり、UIViewやUIApplicationなどのスーパークラスになります。そのためタッチイベントやモーションイベントをこのクラスが管理しています。そのため、UIViewを継承しているUITextFieldやUITextViewはUIResponderのプロパティやメソッド使えることになります。

UIApplicationDelegateプロトコルとは

UIApplicationDelegateプロトコルとは、アプリの共有動作を管理するために使用する一連のメソッドを宣言しているメソッドである。つまりこのプロトコルは、シングルトンのUIApplicationオブジェクトのデリゲートによって実装されるメソッドを宣言し、それらのメソッドは、起動完了時・終了時、メモリの低下、重要な変更の発生など、アプリケーション実行中に置けるキーイベント(重要なイベント)を実行します。

application(_:didFinishLaunchingWithOptions:)とは

関数UIApplicationDelegateに含まれているメソッドのapplication(_:didFinishingWithOptions:)は起動プロセスがほぼ完了し、アプリを実行する準備がほぼ整ったことをデリゲートに伝えます。このメソッドを使用する場合、最後にBool値を返す必要がある。アプリがURLリソースを処理できないかユーザーアクティビティを続行できない場合はfalse、それ以外の場合はtrueを返します。リモート通知の結果としてアプリが起動された場合は戻り値は無視されます。

application(_:didFinishLaunchingWithOptions:)の中の三行について

//ウィンドウをインスタンス化する
self.window = UIWindow(frame: UIScreen.main.bounds)

//メインストーリーボードをロードし、その最初のView Controllerをインスタンス化します。
self.window?.rootViewController = UINavigationController(rootViewController: <表示したいViewContorollerをいれる>)

//新しいView ControllerをウィンドウのrootViewControllerプロパティに割り当ててから、ウィンドウを表示状態にします。
self.window?.makeKeyAndVisible()

上記のコードのように記されている通り、アプリケーションのメインストーリーボードファイルを作成し、それを情報プロパティリストファイルでメインストーリーボードファイルとして識別すると、iOSはいくつかのセットアップタスクを実行することができます。つまりは、起動後最初のViewを表示する動きをしているということです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[cocoa][swift]Tweeting

システム側でのSNS共有のサポートが終了したり、公式のTwitter Kit SDKのサポートが停止するなどで、スマートフォン・アプリケーションにTweet機能を組み込む方法が変わってきているので、今時点のTweet機能を組み込む方法を調べてみた。

  • ios
    • Social.framework
      iOS11から廃止。
    • Twitter Kit SDK
      2018年10月末でサポート終了。
  • Android
    • Twitter Kit SDK
      2018年10月末でサポート終了。

方向としては、ネイティブ・コード向けライブラリの提供はやめて、Web技術を利用して欲しいということのようだ。

iOS

Universal Linksを利用した方法。Twitterアプリケーションがインストールされていない場合はWebブラウザで、インストールされている場合は、Twitterアプリケーションでの投稿となる。

@IBAction func intentTweet(_ sender : Any) {
    let text = "Web Intentの例"
    let encodedText = text.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
    if let encodedText = encodedText,
        let url = URL(string: "https://twitter.com/intent/tweet?text=\(encodedText)") {
        UIApplication.shared.open(url, options: [:], completionHandler: nil)
    }
}

iOSの共有機能を提供するUIActivityViewControllerを利用する方法。Twitterアプリがインストールされていないと候補に現れないだとか、SNS共有っぽくはない。でも、テキストに加え、画像も直に共有できる。

@IBAction func activityTweet(_ sender : Any) {
    let text = "共有機能を利用する"
    let bundlePath = Bundle.main.path(forResource: "brownout", ofType: "jpg")
    let image = UIImage(contentsOfFile: bundlePath!)
    let shareItems = [image, text] as [Any]
    let controller = UIActivityViewController(activityItems: shareItems, applicationActivities: nil)
    present(controller, animated: true, completion: nil)
}

ソースコード
GitHubからどうぞ。

https://github.com/murakami/workbook/tree/master/ios/Tweets - GitHub

【関連情報】
Cocoa Programming for Mac OS X

Cocoa.swift

Cocoa勉強会 関東

Cocoa練習帳

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む