Swift,Objective-Cプログラミング ~ iOS ~

Objective-C,Swift,Apple Watchなどのプログラミング

【iOS Swift入門 #304】iOS11でペースト処理をやりやすくなった(copy paste)

iOS11でのペーストの変更点

iOS11でペーストが使いやすくなりました。

主な変更点

  • UIPasteCongifurationでペーストで受け入れるデータを指定できるようになりました
  • UIResponderを継承しているクラスでpaste(itemProviders: )メソッドを実装できるようになりました

受け入れるデータの指定

UIPasteConfigurationSupportingプロトコルのpasteConfigurationプロパティで指定します。 UIResponderクラスを継承したクラスはUIPasteConfigurationSupportingプロトコルを実装しているので、初期化の際などに指定します。

pasteConfiguration = UIPasteConfiguration(acceptableTypeIdentifiers: [受け入れるデータのID])

paste(itemProviders: )メソッドの実装

下記2つの実装が必要となります。

  • NSItemProviderReadingプロトコルの実装
  • paste(itemProviders: )の実装

実装例

サンプルの概要

コピー 画像とテキストを含むクラスがコピーされます。

ペースト クラスがペーストされます。 f:id:fjswkun:20171209232111p:plain

ペースト後 f:id:fjswkun:20171209232101p:plainf:id:fjswkun:20171209232118p:plain

コピーを実行する画面

import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var imageView: CopyImageView!
    @IBOutlet weak var textField: UITextField!
    
    var item: Item = {
        let imageName = "IMG_6617.jpg"
        let text = "テストアイテム"
        
        return Item(image: UIImage(named: imageName)!, text: text)
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        imageView.image = item.image
        textField.text = item.text
    }
    
    // オブジェクトをDataにエンコードしてコピーする
    override func copy(_ sender: Any?) {
        let data = NSKeyedArchiver.archivedData(withRootObject: item)
        UIPasteboard.general.setData(data, forPasteboardType: Item.itemId)
    }
}

コピー・ペーストするモデルクラス

import Foundation
import UIKit

enum ItemError: Swift.Error {
    case failedEncoding
}

class Item: NSObject, NSCoding {
    // ペースト時に受け入れるID
    static let itemId: String = "com.example.item"
    
    let image: UIImage
    let text: String
    
    required init(image: UIImage, text: String) {
        self.image = image
        self.text = text
        super.init()
    }
    
    public func encode(with aCoder: NSCoder) {
        aCoder.encode(UIImagePNGRepresentation(image), forKey: "image")
        aCoder.encode(text, forKey: "text")
    }
    
    public required convenience init?(coder aDecoder: NSCoder) {
        guard let data = aDecoder.decodeObject(forKey: "image") as? Data,
            let image = UIImage(data: data),
            let text = aDecoder.decodeObject(forKey: "text") as? String
            else {
                return nil
        }
        self.init(image: image, text: text)
    }
}

extension Item: NSItemProviderReading {
    static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> Self {
        switch typeIdentifier {
        case Item.itemId:
            guard let item = NSKeyedUnarchiver.unarchiveObject(with: data) as? Item else {
                throw ItemError.failedEncoding
            }
            return self.init(image: item.image, text: item.text)
        default: throw ItemError.failedEncoding
        }
    }
    
    static var readableTypeIdentifiersForItemProvider: [String] {
        return [Item.itemId]
    }
}

ペーストを実行する画面

import UIKit

class SecondViewController: UIViewController {
    @IBOutlet weak var imageView: UIImageView!
    @IBOutlet weak var textField: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        pasteConfiguration = UIPasteConfiguration(acceptableTypeIdentifiers: [Item.itemId])
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    override func paste(itemProviders: [NSItemProvider]) {
        itemProviders.forEach {
            $0.loadObject(ofClass: Item.self){ object, _ in
                guard let item = object as? Item else {
                    return
                }
                DispatchQueue.main.async { [weak self] in
                    guard let `self` = self else { return }
                    self.imageView.image = item.image
                    self.textField.text = item.text
                }
            }
        }
    }
}

ダウンロード

Googleドライブに保存しています。 ダウンロードして詳細を確認してください。

SampleCopyPaste.zip - Google ドライブ

Swift

入門書籍

絶対に挫折しない iPhoneアプリ開発「超」入門 増補改訂第5版
プログラミングが初めて!という人が小さなアプリを作ることで、アプリ開発を学ぶことができます。
「Swiftだけでなく、プログラミング自体が初めてなんだけど、どの本が良い?」と聞かれたときには、
この書籍をおすすめしています。

本気ではじめるiPhoneアプリ作り Xcode 8.x+Swift 3.x対応 (ヤフー黒帯シリーズ)
アプリ開発からApp Storeへの公開までの一通りを学ぶことができます。
入門書を2冊、3冊を読んだあとでこの書籍を読むとかなりの実力アップを感じることができます。

ただし、一通り学ぶことができますが、プログラミング初めてでこの書籍を選ぶことはオススメできません。
最初の方の内容はプログラミング初心者には理解が難しく、そこで勉強をやめてしまう可能性がありそうだと感じます。

Swiftポケットリファレンス
辞書として1冊は持ってても良い。

仕事でやれるレベルになるために

初心者から仕事でやれるレベルになるためにオススメできる日本語書籍がみつかりませんでした。
英語は苦手でも、書籍に書かれているソースはやさしく、読み進めることができます。

The iOS Apprentice (英語サイト・英語書籍)
Swift Apprentice (英語サイト・英語書籍)

平均的プログラマーを超えるために

詳解Swift 第3版
Swift3の書籍。第1版、第2版にもお世話になっています。
Swiftの文法についてとても詳しく書いてあります。

Ray Wenderlich | Tutorials for iPhone / iOS Developers and Gamers
QiitaのSwiftに関する記事