月別アーカイブ: 2016年11月

【Swift3】配列の番号と剰余算と条件演算子?:

先日、友人の書いたSwiftのコードを見ていた。
その中でやっていることは何となく分かるが、どういう演算子(というのか?)を使っているかわからない部分があった。

やっていることは配列を順番に呼び出すため、配列の番号を1ずつ加えていって配列の最後に来たら最初に戻るというのと、
配列の番号を1つづ引いていって最初まで戻ったら最後の番号に移動するという関数です。

配列の変数はstrArray
番号を入れる変数をpositionとして、

自分が普通に考えたら、if文を使って
最初の加えていく関数は、

    func getNextPositionIf() -> (Int) {
        if position + 1 < strArray.count {
            //positionに1を足したものがstrArray.countより小さければ
            return position + 1
            //positionに1を足したものを返す
        }
        return 0
        //positionに1を足したものがstrArray.countと同じか大きければ?0を返す。
    }

こんな感じで書くかな?

それを友人は

    func getNextPosition() -> (Int) {
        return (position + 1) % strArray.count
    }

と書いていた。

調べてみると、「%」は剰余算の演算子です。
x % Y の場合xをyで割った余りが求められます。

例えば、配列strArrayに入っている要素が5つだとすると、配列の番号positionにはいるのは0,1,2,3,4となる。

positionが3の時、次の番号を求められると、(3+1)わる5 は 0あまり4で4が返される。
positionが4の時、次の番号を求められると、(4+1)わる5 で 1あまり0で0が返される。

うーむ非常にスマートに書かれている。(^_^;)

続いて1ずつ引いていく場合自分が書くと、

    func getPrevPositionIf() -> (Int) {
        if position - 1 < 0 {
            //positionから1を引いて0以下になったら
            return strArray.count - 1
            //strArray.countから1引いたものを返す
        }
        return position - 1
        //それ以外はpositionから1引いたものを返す
    }

こんな感じかな?

それを友人は

    func getPrevPosition() -> (Int) {
        return (position == 0 ? strArray.count : position) - 1;
    }

と書いていた。

(; ・`ω・´)
なんだこれ?なんで一行で?

いろいろ調べた結果、
参考サイト
C言語の演算子について

条件演算子と言うものらしい。

a ? b : c aが真ならbが実行、aが偽ならcが実行。

つまりpositionが0であればstrArray.countから1引いたものを返す、
そうでなければpositionから1引いたものを返す

ということでやってることはif文と同じですね。

しかしスマート。

こういう書き方はふつうにC言語とか習ってる人は知ってるのかなあ?

20数年前のBASICから独学でObjective-cに飛んだ私には分からない(;´∀`)

ま、人様のコードを読むのは勉強になりますね。

【Swift3】【override】と【prepareForSegue】

UITableViewを書いててsegueで遷移する時のprepareForSegueのoverrideがエラーで困った。

Method does not override any method from its superclass
と表示される。
当然overrideしなければprepareForSegueは呼ばれない。

参考サイト
ios – swift 3 prepare(for segue: ) function broken? – Stack Overflow

なんか知らんが書き方が変わったらしい。

    //古い方
//  override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {}
    //↓
    //新しい方
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {}

とゆーことでうまく行った。
うじゃうじゃ。

【Swift3】【UIButton】setTitleのビミョーなアニメーション。

UIButtonに表示される文字は変更できる。

参照サイト
002 UIButtonでボタンを表示 · GitBook

こんな感じだ。

// タイトルを設定する(通常時).
myButton.setTitle("ボタン(通常)", for: .normal)

この時よく見ると?アニメーションで薄くなって消えて新しい文字が現れてくる。

これを止めてぱっぱっと変わってほしかったのだが、なんか無いか調べてみた。

参考サイト
UIButton.setAnimationsEnabled(false)

ぱっと調べた感じ、

UIButton.setAnimationsEnabled(false)

これでアニメーションがなくなるらしい、
しかし、個別のボタンには対応してないようで、さらに縦画面から横画面へのオートレイアウトの遷移のアニメーションもなくなっていた。

使い所を考えてしまう。

【Swift3】【UIPikerView】を下からにゅっと出す。

昔の記事UIPickerViewも下から出す。 | iPhoneアプリ備忘録のSwift3版かな?

参考サイト
011 UIPickerViewで値の選択 · GitBook
閉じるボタンは前回の記事参照。

import UIKit

class ViewController: UIViewController, UITextFieldDelegate, UIPickerViewDelegate, UIPickerViewDataSource {
    
    // UIPickerView.
    private var myUIPicker: UIPickerView!
    // 表示する値の配列.
    private let myValues: NSArray = ["その一","その二","その三","その四"]
    //テキストフィールドを作ってoutlet接続
    @IBOutlet weak var testTextField: UITextField!
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
    // UIPickerViewを生成.
        myUIPicker = UIPickerView()
        // Delegateを設定する.
        myUIPicker.delegate = self
        // DataSourceを設定する.
        myUIPicker.dataSource = self
        
    // testTextFieldのdelegateを設定する。
        testTextField.delegate = self
        
        
    // 閉じるボタンのツールバー生成
        let kbToolBar = UIToolbar(frame: CGRect(x: 0, y: 0, width: 320, height: 40))
        kbToolBar.barStyle = UIBarStyle.default  // スタイルを設定
        kbToolBar.sizeToFit()  // 画面幅に合わせてサイズを変更
        // スペーサー
        let spacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: self, action: nil)
        // 閉じるボタン
        let commitButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.done, target: self, action: #selector(ViewController.commitButtonTapped))
        
        kbToolBar.items = [spacer, commitButton]

        testTextField.inputView = myUIPicker
        testTextField.inputAccessoryView = kbToolBar
    }
    
    //閉じるボタンが押されたらキーボードを閉じる
    func commitButtonTapped (){
        self.view.endEditing(true)
    }

    //PickerViewのコンポーネント(縦)の数を決めるメソッド(実装必須)
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    
    //pickerに表示する行数(横)を返すデータソースメソッド.(実装必須)
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return myValues.count
    }
    
    //pickerに表示する値を返すデリゲートメソッド.
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return myValues[row] as? String
    }
    
    //pickerが選択された際に呼ばれるデリゲートメソッド.
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        testTextField.text = "\(myValues[row])"
        print("row: \(row)")
        print("value: \(myValues[row])")
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

あちこちからのコピペがまるわかり。(^_^;)
一応こんな感じで。

【Swift3】キーボードに閉じるボタン。

UITextfieldやUITextViewでキーボードに閉じるボタンがほしい。

てなわけで参考サイト。
(UITextViewの)キーボードに「閉じる」ボタンを追加する – ながいものには、まかれたくない
iOSでキーボードを閉じる方法各種 – Qiita

ほぼコピペですが、Swift3でちょこっとだけ直されました。

import UIKit

class ViewController: UIViewController, UITextFieldDelegate{
    
    @IBOutlet weak var mainTextView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()
        makeKeybord()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    
    func makeKeybord(){
        // 仮のサイズでツールバー生成
        let kbToolBar = UIToolbar(frame: CGRect(x: 0, y: 0, width: 320, height: 40))
        kbToolBar.barStyle = UIBarStyle.default  // スタイルを設定
        
        kbToolBar.sizeToFit()  // 画面幅に合わせてサイズを変更
        
        // スペーサー
        let spacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: self, action: nil)
        
        // 閉じるボタン
        let commitButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.done, target: self, action: #selector(ViewController.commitButtonTapped))
        
        kbToolBar.items = [spacer, commitButton]
        mainTextView.inputAccessoryView = kbToolBar
    }
    
    func commitButtonTapped (){
        self.view.endEditing(true)
    }
    

よく使いますよね。ヽ(^。^)ノ

【Swift3】【AVSpeechSynthesizer】テキストトゥスピーチってあったよね。

昔MacでTextToSpeechってあったよねー。
懐かしい。

それはさておき、iPhoneでテキストを読ませたいと思います。

参考サイト
AVSpeechSynthesizer – AVFoundation | Apple Developer Documentation
[Swift] iOS でテキストの読み上げをする – Qiita
みんな大好き`AVSpeechSynthsizer`について – Qiita
AVSpeechSynthesizer による音声読み上げ
[Swift] AVSpeechSynthesizerで読み上げ機能を使ってみる | Developers.IO

AVFoundationを使うのでインポート。
デリゲートを使うならAVSpeechSynthesizerDelegate。

import UIKit
import AVFoundation

class ViewController: UIViewController,AVSpeechSynthesizerDelegate {

(中略)

    func utter(str:String) {
    let speech = AVSpeechSynthesizer()
        let utterance = AVSpeechUtterance(string: str)//読み上げる文字
        utterance.voice = AVSpeechSynthesisVoice(language: "ja-JP")//読み上げの言語
        utterance.rate = 0.4 //読み上げの速度
        utterance.pitchMultiplier = 1.2 //声の高さ
        utterance.preUtteranceDelay = 0 //読み上げまでの待機時間
        utterance.postUtteranceDelay = 0 //読んだあとの待機時間
        speech.delegate = self

        speech.speak(utterance) //発話
        }
    
    // デリゲート
    // 読み上げ開始したときに呼ばれる
    internal func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didStart utterance: AVSpeechUtterance) {
        print("読み上げ開始")
    }
    
    // 読み上げ終了したときに呼ばれる
    internal func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
        print("読み上げ終了")
    }
}

読み上げ実行中かどうか
speech.isSpeaking

途中で止める場合
speech.stopSpeaking(at: AVSpeechBoundary.immediate)

【Swift3】Local and Push Notification Programming Guide ??

完成したアプリをアップロードしたが、itunesConnectで出てこない。
メールを見るとiTunes Storeからメールが来ていた。

iTunes Connect: Your app “************” (Apple ID: **************) has one or more issues
Dear developer,

We have discovered one or more issues with your recent delivery for “5TallyCounter”. Your delivery was successful, but you may wish to correct the following issues in your next delivery:

Missing Push Notification Entitlement – Your app includes an API for Apple’s Push Notification service, but the aps-environment entitlement is missing from the app’s signature. To resolve this, make sure your App ID is enabled for push notification in the Provisioning Portal. Then, sign your app with a distribution provisioning profile that includes the aps-environment entitlement. This will create the correct signature, and you can resubmit your app. See “Provisioning and Development” in the Local and Push Notification Programming Guide for more information. If your app does not use the Apple Push Notification service, no action is required. You may remove the API from future submissions to stop this warning. If you use a third-party framework, you may need to contact the developer for information on removing the API.

After you’ve corrected the issues, you can use Xcode or Application Loader to upload a new binary to iTunes Connect.

Regards,

The App Store team

ググる先生で翻訳してみた。
iTunesの接続:あなたのアプリ “************」(アップルID:**************)は、1つ以上の問題があります
親愛なる開発者、

私たちは、 ************のためのあなたの最近の配信を持つ1つ以上の問題を発見しました。あなたの配信に成功しましたが、あなたはあなたの次の配信では、以下の問題を修正したい場合があります。

プッシュ通知エンタイトルメントがありません – あなたのアプリは、Appleのプッシュ通知サービスのためのAPIが含まれていますが、APS-環境エンタイトルメントは、アプリの署名から欠落しています。これを解決するには、アプリケーションIDがプロビジョニングポータルでのプッシュ通知が有効になっていることを確認してください。そして、APS-環境エンタイトルメントが含まれて配布プロビジョニングプロファイルを使用してアプリケーションに署名します。これは、正しい署名を作成し、あなたのアプリを再送信することができます。現地で「プロビジョニングおよび開発」を参照してください詳細については、通知のプログラミングガイドを押してください。あなたのアプリがAppleのプッシュ通知サービスを使用しない場合、アクションは必要ありません。この警告を停止するには、将来の提出からAPIを除去することができます。あなたは、サードパーティ製のフレームワークを使用する場合は、APIを削除する方法については、開発者に連絡する必要があるかもしれません。

あなたが問題を修正した後、あなたは、iTunesのConnectに新しいバイナリをアップロードするのXcodeまたはアプリケーションローダーを使用することができます。

よろしく、

App Storeのチーム

アップロードは受け取ったが Local and Push Notification を使うって聞いてないよ。
なんとかしてアップロードし直してね。ってことらしい。

ちなみに、Local and Push Notification Programming Guideって所にリンクが張ってあったがnot foundだった。

しかし、ノーティフィケーションは使ってない。

色々とぐぐってみたところ、
【xcode】心当たりのない「Missing Push Notification Entitlement」は無視 …

特に使っていないなら問題無さそうだ。
たぶんFirebaseあたりが絡んでるのかなあ?

【Swift3】多言語でアプリ名。

練習用にプロジェクトを作ってやってたら公開までしちゃいそうだけどアプリ名が「FirstSwift」になってる人。
はい。私です。(^_^;)

プロジェクト名そのままではちょっと公開できない場合や、日本語や英語でアプリ名を変えたい場合のやり方です。

参考サイトは
[iOS] アプリ名を国ごと変更したい場合 – Qiita

自分用の備忘録でリンク元が消えちゃったら困る用なので、ほぼ劣化コピペです。

まず、Project > Info > Localizations にて、Japanese(ja)を追加。
%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-11-04-15-00-37

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-11-04-15-01-09

続いてstringsファイルを作成。
%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-11-04-15-02-44
名前はInfoPlist.strings ココ重要!大文字小文字も関係するようです。
%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-11-04-15-03-56

出来たInfoPlist.stringsを選択してlocalizationでJapaneseを選択。
%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-11-04-15-05-07

あらためてlocalizationでEnglishとJapaneseにチェック。
%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-11-04-15-05-37

InfoPlist.stringsを選択してコードを書きます。
BaseがEnglishなので「InfoPlist.strings」と「InfoPlist.strings(English)」は同じ内容になります。

/* 
  InfoPlist.strings
  FirstSwift

  Created by **** on 2016/11/04.
  Copyright © 2016年 ****. All rights reserved.
*/

CFBundleDisplayName = "EnglishName";
/* 
  InfoPlist.strings
  FirstSwift

  Created by **** on 2016/11/04.
  Copyright © 2016年 ****. All rights reserved.
*/

CFBundleDisplayName = "日本語アプリ名";

一回エラーで起動しませんでした。
理由はSwiftのつもりで最後にセミコロンを付けてなかったから。

忘れずにセミコロンを付けましょう。