はつねむさんぽのパンくずたち

エンジニアになる人生で通った道のあしあと

【Swift】もっと読む機能【UILabel】

やりたいこと

「もっと読む」機能を実現するために、UILabelがtruncate(切り捨て)されているか否かを判断したい。 調べてみても、改行対応かつUITableViewCell内でも正確に計算できるものがなかったので。

実装方法

linesはUILabelに指定した行数。 その行数を超える時にtruncateされるので、truncateされなかった場合の高さ(textSize.height)と、最大の高さ(maxHeight)を比較する。

extension UILabel {
    func isTruncated(lines: Int, width: CGFloat) -> Bool {
        guard let labelText = text else { return false }
        let maxHeight = font.lineHeight * CGFloat(lines)
        let textSize = (labelText as NSString).boundingRect(
            with: CGSize(width: width,
            height: .greatestFiniteMagnitude),
            options: .usesLineFragmentOrigin,
            attributes: [.font: font], 
            context: nil
        ).size
        return textSize.height > maxHeight
    }
}

How to せるふまねじめんと

これはTreasure Advent Calendar 2018の10日目の記事です。
技術系の記事書いてる人が多そうなので、違うジャンルで書いてみました。

やらなきゃいけないこと、やった方がいいことを、
ついついサボってしまう私たち向けの記事(主語を大きくするな)。

きっかけ

学校が後期に入り授業が週2になって、急に自分だけの時間が増えた。

勉強したり小説読んだりしたいと思ってるのにいざ朝起きたら、
「一旦漫画読んでから〜」「一旦音楽聴こ」
とか言うてる間に昼寝してる自分に嫌気がさした。

こんな毎日はいやだ!!!!!
しっかり自己管理して、キラキラJDになるぞ☆

せるふまねじめんと

実際に私が大学受験の時にやっていた方法。
我流やし適当なこというてる部分もあります。あしからず。
一部の人に刺さればいいな!

目標を設定する

こうなりたいという目標を設定する。

大学受験の時は確かこうだった。
志望校に合格してキラキラ大学生になる (キラキラとは)

今だったらこう。
技術力を高めてTreasure2019でカッコいいTAになる

「志望校に合格する」とか「技術力を高める」だけじゃなくて、
その先にいるのはどんな自分かまで考えると夢がふくらむ。

自分の学習能力を把握する

「人より理解力が低いから、他の人よりも多くの時間をかけないといけない。」
「人より集中力がないので、早めから始めないといけない。」
みたいな感じ。

ここで「自分は理解力が高い方だ」と思ってしまうのは危険。怠けてしまう。
理解力が高くても、多く時間をかけたり早く始めるに越したことはない。
自分の学習能力を低く低くみるのが大事。

それだけでは、自己嫌悪に陥ってしまうので、
自分は人より能力が低い。でもその分頑張ればできる子!一等賞!
と、脳に言い聞かせることが一番のポイント。
上手にマインドコントロールしましょう(怪しい笑み)。

自分の特性 × 好きなものが最強

個人差がかなり出るが、とても大事な部分。
私の場合を例として紹介する。

まず特性として、「可視化すると頑張れる」というのがあった。
これは割と共感してくれる人多いかな?
本を読んだページ数がグラフ化されるとやる気が出るタイプ。

そしてiPhone(電子機器)が好き!アプリが好き!

これをペンパイナッポーアッポーペンして、
進捗をグラフ化してくれるアプリを導入することにした。
進捗が目に見えて分かるし、記録するのも楽しくて続けられた。

MyStats

MyStats

  • NEOREX Co., Ltd.
  • ビジネス
  • 無料


可視化×絵なら、一章進むごとに絵を書き足して、
一冊読み終わる頃には、なんかすごい絵が完成してるとか面白そう。
可視化×お酒なら、進捗に合わせて各国のビール飲んで瓶コレクションするとか。

心が折れそうになったら・・・

目標の後半部分を妄想して遊ぶ。ニヤニヤする。
(*´﹃`*) < キラキラ大学生になって〜友達100人作って〜たこパして〜うへへ
(大学生なので富士山の上でおにぎりではなく下宿生の家でたこパ)

すんごい浅いけど気にしない。ニヤニヤできたらいい。

まとめ

自分を低く見積もって他人よりやる!
好きなこと絡めながらコツコツ積み重ねるけど、
心が折れそうになった時はうへへへへ(* ´﹃`*)
はい、まとめました。

いやまとめテキトーやな。
もうええわ。ありがとうございました。

バイトのiOS&WEB開発再開

iOSアプリ開発

iOSアプリ開発が始まった。
やっぱりSwift楽しいな。
今日の知見はこんな感じ。
動画周りは始めた触るので学びがある。

気づいたら、7時間ぶっ通しで開発してた。

夜は短し歩けよ乙女

京都、京都大学を舞台にした小説。
半年くらい読んでなかったけど、最近また読み始めた。
今は学祭NFの章。
「わかるー!笑」ってシーンがあって面白い。

【Swift】動画撮影&保存&取得【UIImagePickerController】

やりたいこと

アプリ内で動画を撮影し保存。
また、アプリ内で撮影した動画のみを取得。

実装方法

動画撮影

動画周りはややこしいイメージがあったが、
UIImagePickerControllerを使えば意外と簡単に実装できた。

let sourceType = UIImagePickerController.SourceType.camera
// 端末でカメラが利用可能か調べる
if UIImagePickerController.isSourceTypeAvailable(sourceType) {
    let pickerController = UIImagePickerController()
    pickerController.delegate = self
    pickerController.sourceType = sourceType

    // ここで動画を選択
    pickerController.mediaTypes = ["public.movie"]
    // 以下のようにすると、利用可能な全てのmediaTypeが選択できる
    // pickerController.mediaTypes = UIImagePickerController.availableMediaTypes(for: sourceType) ?? []

    // 動画を高画質で保存する
    pickerController.videoQuality = .typeHigh
    present(pickerController, animated: true, completion: nil)
}

動画保存

撮影した動画はAppData内のtmpフォルダ(一時フォルダ)に置かれているので、
Documentフォルダに移動する。
カメラロールに保存するよりもアプリ内動画一覧の取得が実装しやすい。
あとで必要なものだけカメラロールにエクスポートする方法をとった。

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    picker.dismiss(animated: true, completion: nil)
    
    // 一時フォルダに保存されたファイルのURL
    guard let fileUrl = info[.mediaURL] as? URL else { return }
    // DocumentフォルダのURL
    let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    do {
        //  tmpに保存された動画をDocumentに移動
        try FileManager.default.moveItem(at: fileUrl, to: documentsDirectoryURL.appendingPathComponent(fileUrl.lastPathComponent))
        print("動画の保存に成功しました。")
    } catch {
        print("動画の保存に失敗しました。")
    }
}

動画取得

Documentフォルダ内のファイルのURLを全て取得する。

var videoUrls = [URL]()

let documentDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
do {
    // Documentから動画ファイルのURLを取得
    videoUrls = try FileManager.default.contentsOfDirectory(at: documentDirectoryURL, includingPropertiesForKeys: nil)
} catch {
    print("フォルダが空です。")
}

取得したURLを使って、動画を再生したり、一覧を表示したりできる。
Collection Viewにサムネイル一覧を表示するならこんな感じ。

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "videoCell", for: indexPath)
    
    // URLから動画を取得
    let video = AVURLAsset(url: videoUrls[indexPath.row])
    // 動画から静止画を切り出すジェネレータ
    let generator = AVAssetImageGenerator(asset: video)
    // 今回は00:00の部分を切り出し
    let thumbnail = try! generator.copyCGImage(at: .zero, actualTime: nil)
    
    let thumbnailView = cell.viewWithTag(1) as! UIImageView
    thumbnailView.image = UIImage(cgImage: thumbnail)
    
    let label = cell.viewWithTag(2) as! UILabel
    let sec = Int(video.duration.seconds)
    label.text = String(format:"%02d:%02d", sec/60, sec%60)
    
    return cell
}

自分の声を解析した

Java環境構築 on Mac

今日から本格的に実験が始まった。
謎のこだわりでVSCodeJava書こうとしたら、
環境構築にすんごい手間取ってしまった。

JDK11はJavaFXが含まれていないみたい。仕方ないからOpenJFX入れた。
コンパイルとビルドする時に、いちいちオプション付けるのめんどくさいな。
設定ファイルとか書けばいいのか?
そもそもバージョン落とした方がいい説。

 

音声処理

自分の声の音量(dB)と音高求めた。
まずこれが波形。「あ・い・う・え・お」と言っている。
8秒以降は雑音だ。(トリミングしろよ。。。)

f:id:hatsunem:20181130214629p:plain
波形(横軸:時間[秒]、縦軸:振幅)
 

フレームに分割して各フレームの音量を求めた。
音量(dB)は、振幅の2乗の平均の平方根の常用対数をとって20かけたものである。
つまり、20\log{10}\sqrt{\frac{1}{N}\sum_{t=0}^{N-1} x_t}
ルートの部分をRMS(root-mean-square)という。

f:id:hatsunem:20181130231047p:plain
音量(横軸:時間[秒]、縦軸:音量[dB])
 

次に自己相関を利用して音高を求めた。
自己相関は、ある信号とその信号を時間方向にシフトした信号との類似度を表す。
自己相関が2番目に大きい時のシフト時間の逆数が基本周波数となる。

f:id:hatsunem:20181130235933p:plain
音高(横軸:時間[秒]、縦軸:基本周波数)

雑音の部分の音高が様々で、グラフがごちゃごちゃしてしまった。
振幅で制限をかけて、ある程度小さいものは除去すると良さそう。  

スタート地点

今日から日記書く

就活終わって、いったん落ち着いたから、

自分磨きのために日記を書き始めることにした。

目標は「来年のTreasureでカッコいいTAになる」こと!

 

WEBの勉強始める

まずはWEB周りの勉強から始めようと思う。

今までSwiftばかり書いてきたので。

さっそくオススメしていただいた、「Real World HTTP」を購入した。

初めて技術書というものを手に入れてわくわくしてる。

こつこつ勉強するぞ。

 

計算機科学実験4後半戦

学校の実験の後半戦が始まった。今回のテーマは「音楽情報処理」。

簡単な言えばカラオケ作り!!!

授業中に歌って性能確かめあかんのは嫌やけど、音声処理するの楽しみ!

 

セルフマネジメント

今までの、お昼まで寝てる生活を改善するべく、

まいふぉんにmy statsというアプリをインストールした。

大学受験の時に使ってたアプリ。

"可視化するとなんか頑張れる"という私の特性を活かした作戦。

あの時めっちゃ受験勉強頑張れたから、今回も役立ってくれるはず、、、!!!

 

楽天(大阪)のインターンに参加した

インターン概要

就業型のインターンである。
実際に社内のチームに入れてもらい、開発を進めた。
最終日には、インターンを通して行ったことを発表した。

期間や出勤曜日は社員の方と相談しながら決められるので、
学校が始まった10月からでもインターンに参加することができた。
私は10月から約一ヶ月間、月火水で働かせてもらった。

とても良い経験になった

チーム開発

朝は部署全体で"Asa-kai"と呼ばれる朝礼を行い、連絡事項の報告し、
夕方にはチームで"Huddle"行って、進捗報告とミーティングをした。
実際のチームに入れてもらったことで、働くイメージをつかむことができた。

メンターさん

メンターさんはとてもとてもいい人だった😭✨
いつ質問してもすぐに対応してくれた。

感動したのは、プロダクトに使われている技術が興味あるものだったので、
もっと知りたいと言った時に、すぐに勉強会をセッティングしてくれたことだ。
私の声を聞いてくれるメンターさんもすごいし、
それで資料を作って教えてくれる社員さんもすごいし、
勉強会に参加する他の社員さんたちもすごいし、
そういうことがすぐにできる会社の環境もすごいなと思った。

マネージャさんとの面談

週に一回マネージャさんとの面談があった。
これはインターン生だけに限らず、社員の方とも行なっているようで、
現在の状況や、抱えている悩みを相談できる場のようだ。

私はインターン中の面談を通して、キャリアプランについて話した。
楽天という大企業のインターンに参加しておきながら、
「最初はベンチャーに就職したいです!!」(嘘はつけない性分)
という私にも親身になって相談に乗ってくれた。
10年後20年後の将来まで考えるきっかけとなった。

最終発表

英語での発表だった。
最初はびっくりしたが、高校でおじいちゃん先生に発表資料の作り方や
英語でのプレゼンの仕方をしごかれた経験を活かすことができた。
社員の方々に褒められて嬉しかった。
「これまで見た中で最もよくまとまっていて分かりやすかった」
という評価をいただけてホクホクした。

おもしろい文化

英語

楽天は多様な国籍の社員が働いていることで有名だ。
チームに一人以上は外国人がいるし、逆に日本人が一人だけのチームもあった。
英語でのやり取りには刺激を受けた。やっぱり英語喋れるとかっこいい。

ただ、いつでもどこでも英語という訳ではなかった。
日本語が話せる人に対しては、ガンガン日本語で話していた。
英語しか話せない人と話すときに英語を使う、という感じ。

しかし、公用語は英語に設定されているので、
プレゼンなどは全て英語が義務付けられていた。
あくまで"公用"ということか。

普段からバリバリ英語を使うわけではないので、
社員の方々の英語力はあまり高くないように思った。
この辺は少し混沌としている印象を受けた。

ハロウィン

外国人がたくさん働いていることに由来するのかは不明だが、
ハロウィンなどのイベントも盛んだ。

私は運良く、10/31に出勤することができた。
社員の方々が本気のコスプレで出社していたのは笑った。
血まみれのナース(男性)、KIRIMIちゃん、武士、駅員さん、などなど、、、
どうやら社内で👻仮装コンテスト🎃があるらしい。
ちなみに私はピカチュウになったw

お仕事だけでなく、こういったイベントを楽しめる雰囲気はいいなと思った。

まとめ

楽天インターンに参加したことで、視野が広がった。
また、自分の将来についてふわっと考えていたことが、しっかりと見えてきた。
インターン中に関わってくれた社員の方々にはとても感謝している。
参加できてよかった。