2018年1月15日月曜日

使ってみた(App Extension編) その1

「コンテキストメニューを置き換えてみた」の続編になります。

UITextViewのコンテキストメニューのカスタマイズはできたものの、WKWebViewではできなかったというところで終わってました。何とかならないかなぁと思っていたのです。

あ、App Extensionで「共有」に追加でき、、、?

それや!

App ExtensionはiOS8で追加された機能ですが、使ったことがなかったので思いつかなかったです。

ここではApp Extensionについてのざっくりとした話題だけですので、詳細についてはAppleの「App Extensionプログラミングガイド」を参照してください。

--

登場人物は3人です。

  1. ホストアプリケーション(Host app)
  2. App Extension
  3. 収容アプリケーション(Containing app)

1.のホストアプリケーション(Host app)は、例えばSafariやメモappなど、App Extensionを呼び出す側のアプリです。

3.の収容アプリケーション(Containing app)は、App Extensionを備えたアプリで、いわゆる「アプリ」です。

App Extensionは、収容アプリケーションのプロジェクトに含まれていますが、収容アプリケーションとは独立して動きます。

ホストアプリケーションは、収容アプリケーションを呼び出すのではなく、App Extensionを呼び出してやりとりするだけで、収容アプリケーションが起動されるわけではないというところが肝でしょうか。

--

さっそく、テストアプリを作ってみます。

ホストアプリケーションはとりあえず、Safariを使います。
収容アプリケーションは、AwesomeAppというアプリにしてみます。


いつもどおり、普通にAwesomeAppというプロジェクトを作成したら、App Extensionを新しいターゲットとして追加します。シンプルにShare Extensionにします。

File > New > Target で、Share Extensionを選択します。

ターゲットとして追加

Share Extensionを選択


ターゲット名は自由に決められますが、「収容アプリケーション+機能」がわかりやすいと思いますので、AwesomeAppShareにしました。



AwesomeAppShareのテストのスキームを作成するか否かのダイアログが表示されるので、'Activate'を選択します。

Activateを選択
ターゲットが追加されました

このApp Extensionのターゲットの中には、3つのファイルが生成されています。

  • ViewController
  • Storyboard
  • info.plist
--

ひとつ、はまりどころとしては、Deployment Targetがあります。

App Extensionと収容アプリケーションのDeployment Targetが同じになっているか確認するのを忘れないでください。

ターゲットの追加時には、デフォルトのDeployment Targetになります。既存のアプリにターゲットを追加するときには、同じにならないことがありますので、要確認です(テストで、はまりましたよ)。

--


たったこれだけですが、とりあえず動きます。


スキームを「(E)AwesomeAppShare」に設定して、実行します。

(E)AwesomeAppShareに変更


ホストアプリケーションが選択できるので、Safariを選んでRunを押します。



Safari(ホストアプリケーション)が起動するので、適当な文言を選択してから、Shareを選択します。

Shareを選択


AwesomeAppShareのアイコンがあるので、タップ。

※ここではアイコンがデフォルトのものになっていますが、収容アプリケーションにアイコンが設定されていれば、そのアイコンが自動的に表示されます。



Share Extensionが起動します。

選択した文言が取得できています


コーディングなしで、ここまでできました。ただ、ここで動いているのはあくまでShare Extension(AwesomeAppShare)です。収容アプリケーション(AwesomeApp)は、全く動いてません。念のため。


今回はここまで。


「使ってみた(App Extension編) その2」に続きます。


♪♪♪


こちらもどうぞ。
使ってみた(App Extension編) その2
使ってみた(App Extension編) その3
使ってみた(App Extension編) その4
使ってみた(App Extension編) その5
使ってみた(App Extension編) おまけ

iOS 11 Programming
  • 著者:堤 修一,吉田 悠一,池田 翔,坂田 晃一,加藤 尋樹,川邉 雄介,岸川克己,所 友太,永野 哲久,加藤 寛人,
  • 発行日:2017年11月16日
  • 対応フォーマット:製本版,PDF
  • PEAKSで購入する


2017年12月15日金曜日

コンテキストメニューを置き換えてみた

作成中のアプリで、UITextViewのコンテキストメニューに機能を追加したいと思いまして。

こういうの

調べたところ、touchesBeganとcanPerformActionをオーバーライドすればカスタマイズできそうとのことなのでこんな感じにしてみました。
protocol CustomedMenuTextViewDelegate: class {
    func customedMenu1(selectedText: String)
    func customedMenu2(selectedText: String)
    func customedMenu3(selectedText: String)
}

class CustomedMenuTextView: UITextView {
    
    weak var customedMenuDelegate: CustomedMenuTextViewDelegate?

    override func touchesBegan(_ touches: Set, with event: UIEvent?) {
        let menuController = UIMenuController.shared
        menuController.setTargetRect(CGRect.zero, in: self)
        menuController.arrowDirection = .down
        
        let menuItems = [
            UIMenuItem.init(title: "Menu1", action: #selector(menu1Selected(sender: ))),
            UIMenuItem.init(title: "Menu2", action: #selector(menu2Selected(sender: ))),
            UIMenuItem.init(title: "Menu3", action: #selector(menu3Selected(sender: ))),
            ]
        menuController.menuItems = menuItems
        menuController.setMenuVisible(true, animated: true)
    }
    
    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        if action == #selector(menu1Selected(sender: )) ||
           action == #selector(menu2Selected(sender: )) ||
           action == #selector(menu3Selected(sender: )) {
            return true
        }
        
        return false
    }
    
    // MARK: - ACTION EVENT METHOD
    
    @objc private func menu1Selected(sender: Any) {
        guard let _ = sender as? UIMenuController else {
            print("error1")
            return
        }
        
        let selectedText = self.text(in: self.selectedTextRange!)!
        if let d = customedMenuDelegate {
            d.customedMenu1(selectedText: selectedText) //選択された文字列を返す
        }
    }
    
    @objc private func menu2Selected(sender: Any) {
        guard let _ = sender as? UIMenuController else {
            print("error2")
            return
        }
        
        let selectedText = self.text(in: self.selectedTextRange!)!
        if let d = customedMenuDelegate {
            d.customedMenu2(selectedText: selectedText) //選択された文字列を返す
        }
    }
    
    @objc private func menu3Selected(sender: Any) {
        guard let _ = sender as? UIMenuController else {
            print("error3")
            return
        }
        
        let selectedText = self.text(in: self.selectedTextRange!)!
        if let d = customedMenuDelegate {
            d.customedMenu3(selectedText: selectedText) //選択された文字列を返す
        }
    }
}

呼び出す側はこうします。

class ViewController: UIViewController, CustomedMenuTextViewDelegate {

    @IBOutlet weak var textView: CustomedMenuTextView!
    
    // MARK: - UIViewController: RESPONDING TO VIEW EVENTS
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        textView.isEditable = false
        textView.customedMenuDelegate = self
    }

    // MARK: - UIViewController: HANDLING MEMORY WARNINGS
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // MARK: - METHODS FOR CustomedMenuTextViewDelegate
    
    func customedMenu1(selectedText: String) {
        print("Menu1: selected text = " + selectedText)
    }
    
    func customedMenu2(selectedText: String) {
        print("Menu2: selected text = " + selectedText)
    }
    
    func customedMenu3(selectedText: String) {
        print("Menu3: selected text = " + selectedText)
    }
}

もう少し汎用性を持たせたいところですが、とりあえず動作するようなので我慢します。


こうなりました

Appleによる正規の方法ではなさそうです。

WKWebView(deprecatedだけどUIWebViewでもいいけど)でも、同じことをしたかったのですが、この方法ではダメでした。残念。

良い方法ないですかね?


「使ってみた(App Extension編) その1」に続きます。

iOS 11 Programming
  • 著者:堤 修一,吉田 悠一,池田 翔,坂田 晃一,加藤 尋樹,川邉 雄介,岸川克己,所 友太,永野 哲久,加藤 寛人,
  • 発行日:2017年11月16日
  • 対応フォーマット:製本版,PDF
  • PEAKSで購入する


2017年12月1日金曜日

チューニングなどという(貴族編)

「思うところあって」と、ギターのチューニングについて書いてきました。

チューニングなどという(まずは基本ですよ編)
チューニングなどという(これはアカン編)
チューニングなどという(そしてリベンジ編)
チューニングなどという(だからチューナー編)


まぁ、自分のアプリのPRのために書いたわけですけど。最後は、その「思うところ」をふたつばかりちょっと。


ひとつめは、「これはアカン編」で書いた、ハーモニクスを使ったチューニング方法はだめだということ。

今どきチューナーも安いですし、みんな使ってるだろと思っていたのですが、YouTubeを見ると、「ちょっと通っぽいチューニング方法」みたいな体でハーモニクスでのチューニングを披露していたりするわけです。何人も。中には、ギタースクールの講師と称する人すらいたりするのです。そして再生回数もかなり稼いでいます。


あかんでしょ、これ(笑)。


ま、それがこの一連のシリーズを書くきっかけだったわけです。


ふたつめは、初心者がチューニングメーターを使うことに反対する方がいることです。

自分の耳でチューニングすることで耳を鍛えることができるんだ、という主張です。もちろん考えは人それぞれですが、それはちょっとどうでしょうか。

そもそも、チューニングで耳を鍛える(音感を鍛える)、ってなに?

今まで書いてきたように、ギターのチューニングなんて二つの音が同じになるように調節することです。わんわん鳴る唸りが出ないようにユニゾンでぴったり合わせるだけのことです。

ギターの音に耳をすまして集中すること自体は良いことですし、大切なことだとは思いますが、それってチューニングでやる必要があるでしょうか。

僕は、初心者こそチューニングメーターを使うべきだと思ってます。

そもそも、音感を鍛えると言ったって、正しくチューニングされていないギターを、初心者がああでもないこうでもないとペグを回したところで、耳が鍛えられるなんてことは考えにくいです。時間の無駄ですよ。さっさとチューナーで正しく合わせて、少しでも多く練習した方が、よほどマシです。

例えば、ピアノを学ぶ人は、まず、ピアノの調律を学ばなければならないなんてことはないでしょう?それともピアニストは音感が悪いのでしょうか?

チューニングは、楽器を演奏するための準備であって、練習でもトレーニングでもありません。

ギターに限らず、初心者にとって最も大切なことのひとつは、正しくチューニングされた楽器を弾くことだと思います。普段から正しくチューニングされた楽器を弾くことで、正しい状態が身について、そしてもし合っていないときに「あれ、おかしいな?」ってわかるようになると思うのです。

つまり、正しくチューニングされた楽器によって音感が磨かれるのであって、音感を磨くのにチューニングをするのではないです。結果と過程をすり替えてはいけないと思います。


”そう、チューニングなどという雑事は、使用人 チューナー に任せておけば良いんですよ。” 
by 貴族探偵





2017年11月15日水曜日

Swift、フォー!

「フォー!」って叫んでたあの芸人さん、最近見ませんね。僕があまりテレビを見ないから、そう思うだけかもしれませんけど。


Xcode9になって、Swift4が使えるようになりました。

Swift3で書かれたプロジェクトを開くと、Swift4への変換のメッセージがでます。

なんだかframeworkやCocoaPodsも巻き込んでいきそうな感じです。以前のSwiftのアップデート時には、派手にソースが変更されて冷や汗をかきました。

今回ももしやと、びくびくしながら続けていくと、大した変更はありませんでした。

変換された部分は、#selector()で指定しているイベントのアクションの関数の定義に、@objcが付けられた程度です。

    //略
    let nc = NotificationCenter.default
    nc.addObserver(self,
                   selector: #selector(Foo.bar),
                   name: "piyo"
                   object: nil)
    //略
    @objc func bar() {
        //略
    }
    //略

しかし、なぜ@objcなんでしょうか。このプロジェクトはすべてSwiftで書かれていますし、何だか腑に落ちないです。どこから来たのobjc属性。

しかも追加された@objcの箇所にワーニングが出力されます。何か間違ってませんか?


Selector Expression
A selector expression lets you access the selector used to refer to a method or to a property’s getter or setter in Objective-C.

#selector(method name)
#selector(getter: property name)
#selector(setter: property name)

The method name and property name must be a reference to a method or a property that is available in the Objective-C runtime. The value of a selector expression is an instance of the Selector type.

(“The Swift Programming Language (Swift 3.1)”/Apple Inc.より)


ふむふむ。


セレクタはObjective-Cの概念であるため、Selector型を生成するにはメソッドがObjective-Cから参照可能である必要があります。メソッドをObjective-Cから参照可能にするには、objc属性を指定します。

(Swift実践入門/石川洋資,西山勇世 P289より)


なるほど。

どこかからObjctive-Cが湧いてきたわけではなく、そもそもセレクタはObjecive-Cのランタイムにおける概念なのですね。

これはSwift4の書式に変換してくれたというより、本来必要だった@objcを、厳しくなったコンパイラのために付けてくれたということなのでしょう。


試しに、@objcを削除してみるとエラーになります。

Argument of '#selector' refers to instance method 'bar()' that is not exposed to Objective-C
Add '@objc' to expose this instance method to Objective-C


ちなみに、objc属性の箇所のワーニングですが、

The use of Swift 3 @objc inference in Swift 4 mode is deprecated. Please address deprecated @objc inference warnings, test your code with “Use of deprecated Swift 3 @objc inference” logging enabled, and then disable inference by changing the "Swift 3 @objc Inference" build setting to "Default" for the "xxxxxx" target.

これは、TARGETSのBuild Settingsをswiftで検索して、Swift 3 @objc Inference(Onになっていると思います)を、Defaultにすると消えます。



これで安心してSwift4を使えますね。




2017年11月1日水曜日

チューニングなどという(だからチューナー編)

チューニングについて書いてきましたが、初心者にとって、ギターを正しくチューニングするのは、なかなか大変です。


そこでチューニングメーターですよ。奥さん。


市販されているものはだいたい大丈夫だと思うので、特別高価なものである必要はありません。利用する状況に応じて決めると良いのではないでしょうか。例えば、エレキギターならシールドを直接つなぐことができるタイプとか、アコースティックギターならクリップ式のものだとか。

クリップ式だと、ちょっと古いですがKORGのAW-1を持っています。アコースティックギターはもちろん、ソリッドボディーのエレキギターでも大丈夫です。ヘッドというかネックって、思っている以上に振動してるんですね。あと、メーターが機械式じゃないもの方が、少しくらい雑に扱っても故障しにくいかもしれません。

どれもちょっと古いですが。

普段のチューニングに加えて、エレキギターの場合はオクターブチューニングが必要です(あ、いや、アコースティックギターでも本来必要ですが、自分でやる人は少ないと思います。僕もやったことはないです)。つまりサドルの調整ですね。最低でも弦を交換したタイミングでは行うべきです。これはチューナーなしでは無理です。工夫すれば、できなくはなさそうですが、そんなこと普通はやらないでしょう。素直にチューナーを使いましょう。21世紀なんですから。

チューナーの使い方ですが、合わせたい音を設定する方法は機種によって違いますが、メーターの見方は同じです。針が真ん中が音があっている状態、左が低い(フラット)、右が高い(シャープ)です。

アプリのヘルプ用に作った動画があるので、よかったら見てみてください。(画質が良くないのは、スマホ用に少しでもパケットを節約して見てもらえるようにするためなので、許してください)

合わせたい弦を、びーんと鳴らしたとき、針が真ん中より左を指していたら、ゆっくりとペグを巻き上げて、中心を指すようにします。

もし、真ん中より右を指しているときは、ギターの音が高いので、ペグを回して緩めればいいわけです。でも、音を合わせるときには「低い方から巻き上げながら合わせる」というのがお約束でしたから、一度針が左側に来るまで緩めてから、ゆっくりと巻き上げながら針を真ん中に合わせるのがいいと思います。


こんな感じで、チューナーがあればチューニングを素早く簡単にできます。そして何より正確です。必携です。




「チューニングなどという(貴族編)」に続きます。

2017年10月15日日曜日

帰ってきた凛としてSwift(くるくる編)

泣きながらiPhoneX対応をしています。なんであんなにワーニングが出るんでしょうか、Xcode9のStroyboard。

ウェブページを表示する画面を作っていたのですが、また見慣れないSwiftLintのワーニングが出たので、シリーズ続行です。


UIWebViewがdeprecatedになったので、WKWebViewを使うことにしました。

ページのロード中を示すインジケータの表示ですが、UIWebViewならUIWebViewDelegateを実装すれば開始と終了のイベントが取得できるので、丸いアニメーションインジケータを表示するのが簡単だと思います。WKWebViewでも、WKNavigationDelegateを実装すれば同様にコントロールできます。

(※ 今回のソースは全てSwift4で、最小限動くところまで削るためにターゲットをiOS11.0以降にしました。ご注意を。)

import UIKit
import WebKit

class SomeWeb4ViewController: UIViewController, WKNavigationDelegate {

    @IBOutlet weak var webView: WKWebView!
    @IBOutlet weak var indicatorView: UIActivityIndicatorView! //くるくるインジケータ
    
    override func viewDidLoad() {
        super.viewDidLoad()

        indicatorView.hidesWhenStopped = true //くるくるしてないときは、非表示
        
        //webページのロード
        webView.navigationDelegate = self
        let myURL = URL(string: "https://www.apple.com/")
        let myRequest = URLRequest(url: myURL!)
        webView.load(myRequest)
    }
    
    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        indicatorView.startAnimating() //くるくる開始
    }
    
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        indicatorView.stopAnimating() //くるくる停止
    }
}
まぁ、見たとおりです。WKNavigationDelegateで、Webページのロードの開始と停止のイベントを取得しています。処理もシンプルで分かりやすいですね。

ただ、WKWebViewはKVOに対応しているので、もう少し気の利いた制御をするのがお約束なのでしょうか。そんな情報が多いです。そこで、それらを真似てナビゲーションバーの下に、横に伸びるインジケータ表示にしました。

import UIKit
import WebKit

class SomeWeb2ViewController: UIViewController {

    @IBOutlet weak var webView: WKWebView!
    
    var progressView = UIProgressView()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        //プログレスバー
        let progFrame = CGRect(x: 0.0,
                               y: self.navigationController!.navigationBar.frame.size.height - 2.0,
                               width: self.navigationController!.navigationBar.frame.size.width,
                               height: 10.0)
        progressView = UIProgressView(frame: progFrame)
        progressView.progressViewStyle = .bar
        self.navigationController?.navigationBar.addSubview(progressView)
        
        //ここで、webViewのobserverを設定して
        webView.addObserver(self, forKeyPath: "loading", options: .new, context: nil)
        webView.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil)

        //webページのロード
        let myURL = URL(string: "https://www.apple.com/")
        let myRequest = URLRequest(url: myURL!)
        webView.load(myRequest)
    }
    
    //ここで進捗を受信
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "estimatedProgress"{
            progressView.setProgress(Float(webView.estimatedProgress), animated: true)
        } else if keyPath == "loading"{
            UIApplication.shared.isNetworkActivityIndicatorVisible = webView.isLoading
            if webView.isLoading {
                progressView.setProgress(0.1, animated: true) //プログレスの開始
            } else {
                progressView.setProgress(0.0, animated: false) //プログレスを消去
            }
        }
    }
    
    deinit {
        webView.removeObserver(self, forKeyPath: "estimatedProgress")
        webView.removeObserver(self, forKeyPath: "loading")
    }
}
webViewに、"loading"と"estimatedProgress"のobserverを付加して、ロードの開始、進捗、終了を取得しています。

ちなみにdeinitにある、observerの削除がないと落ちるとのことですが、11.0では落ちなかったです。だから不要、というわけでもなさそうですが。

もちろんこれでちゃんと動作するのですが、SwiftLintがワーニングを出力します。


・block_based_kvo
Block Based KVO Violation: Prefer the new block based KVO API with keypaths when using Swift 3.2 or later. (block_based_kvo)


new block based KVO API with keypaths ってなに?って感じですが、 どうやらWKWebViewに付加したobserverを func observeValue(){} で受信する方法は古いようです。

そこで、Adopting Cocoa Design Patternsの「Key-Value Observing」を参考にして、 NSKeyValueObservationを使った方法に書き換えてみました。
import UIKit
import WebKit

class SomeWeb3ViewController: UIViewController {
    
    @IBOutlet weak var webView: WKWebView!
    var progressView = UIProgressView()
    
    var obsLoading: NSKeyValueObservation? //←これ
    var obsEstimatedProgress: NSKeyValueObservation? //←これ
    
    override func viewDidLoad() {
        super.viewDidLoad()

        //プログレスバー
        let progFrame = CGRect(x: 0.0,
                               y: self.navigationController!.navigationBar.frame.size.height - 2.0,
                               width: UIScreen.main.bounds.size.width,
                               height: 10.0)
        progressView = UIProgressView(frame: progFrame)
        progressView.progressViewStyle = .bar
        self.navigationController?.navigationBar.addSubview(progressView)
        
        //ここから→
        obsLoading = observe(\.webView.loading) { _, _ in
            UIApplication.shared.isNetworkActivityIndicatorVisible = self.webView.isLoading
            if self.webView.isLoading {
                self.progressView.setProgress(0.1, animated: true) //プログレスの開始
            } else {
                self.progressView.setProgress(0.0, animated: false) //プログレスを消去
            }
        }
        obsEstimatedProgress = observe(\.webView.estimatedProgress) { _, _ in
            self.progressView.setProgress(Float(self.webView.estimatedProgress), animated: true)
        }
        //←ここまで

        let myURL = URL(string: "https://www.apple.com/")
        let myRequest = URLRequest(url: myURL!)
        webView.load(myRequest)
    }
}
Swift4におけるKVOのベストプラクティスがよくわかっていないので、本当にこれが正しいのか自信がないのですが、とりあえずワーニングが消えて、ちゃんと動きました。内心、ちょっと怪しいとは感じています。ま、そのときはそのときで随時修正します。

それにしても、なにこのバックスラッシュ。Swiftこわい。


♪♪♪


こちらもどうぞ。
凛としてSwift
凛としてSwift (血闘編ノ壱)
凛としてSwift (血闘編ノ弐)
凛としてSwift (血闘編ノ参)


2017年10月1日日曜日

チューニングなどという(そしてリベンジ編)

前回の「チューニングなどという(これはアカン編)」で、ハーモニクスを使ったチューニング方法はダメだという話を書きました。今回は、じゃあそれは何の役にも立たないかというかというと、「ちょっと待て、そこは考えどころじゃないか?」という話です。

また、5弦を基準に4弦を合わせる場合に限定して書きます。

正しいチューニング方法では、5弦の5フレットの実音に4弦の開放を合わせるというのは「チューニングなどという(まずは基本ですよ編)」で書きました。

そして、ハーモニクスを使ったチューニング方法では、5弦の5フレットのハーモニクスに4弦の7フレットのハーモニクスを合わせるのでした(でも実際は4弦が少しだけ低くなってしまう)。



そして、2つの音を同じにするよう合わせるには、音を同時に出して唸りがなくなるようにすれば良いことも書きました。

ここからは実際にチューニングをする時の動作についてです。

実音を使った正しいチューニングでは、5弦の5フレットを左手で押さえていないといけないので、ふたつの音を聞きながらペグを回すことはできません。右手でペグを回すという手もありますが、それでは両手が交差して大変ですし、5フレットを押さえている左手に変に力が入って音程も安定しないでしょう。そんなわけで、音をチェックしてはペグを回し、音をチェックして回し、の繰り返しになります。

うむ、これはそういうものなのでしょうがないですな。うんうん。

それに対して、ハーモニクスを使った方法は、音を出している間左手が自由になりますから、音を聞きながらペグを回すことができます。これはちょっと便利ですよね。

そこで、だいたい近いところまではハーモニクスを使ってから、仕上げに実音を使ったチューニングで確認するというのはどうでしょう。

ハーモニクスを使った方法は、基準となる5弦から高い方の4弦を合わせるとき、ピッタリ合わせても、4弦が正しい音程よりも少し低くなるのでした。そこで、そこからは実音でチェックしながら、少しずつ4弦を上げていって合わせるといった方法です。

ペグを回す時は低い方から巻き上げていって、正しい音に合わせるというのがお約束でしたが、これにも馴染みます。

基準となる弦から低い方の現に合わせるとき、つまり5弦の7フレットのハーモニクスに、6弦の5フレットのハーモニクスを合わせる時ですが、この場合はぴったり合わせてしまうと、6弦が少し高くなってしまうので、少し手前でやめて、そこからは、やっぱり実音で確認しながら少しづつ上げていくのがいいと思います。

ハーモニクスでざっくり合わせて、実音で正確にチェック。これですよ。

普段ギターの弦は、張りっぱなしにしている人が多いと思いますが、「ネックが弱いので、弾かないときは弦を緩めておかないとちょっと不安なんだよね」というような方は、この"ハーモニクスでざっくり、実音で正確に"というやり方は便利なのではないでしょうか。そうでなくても、弦の交換時など、全くチューニングがあっていない状態からチューニングする時には役に立ちそうです。

今回は、役に立たないチューニング方法を、なんとか使えないものかという視点で考えてみました。どうでしょうか。





「チューニングなどという(だからチューナー編)」に続きます。