読者です 読者をやめる 読者になる 読者になる

Pychef's Diary

I consider myself an engineer, aren't I?

iOS8 SimulatorでだけWKWebViewが動作しなかった話 - WKWebView on iOS 8 Simulator doesn't work?

症状

WKWebViewが、iOS 8 Simulatorでだけ何も表示せず真っ白 * iOS 9 Simulatorは問題なし * estimatedProgressは、いきなり1.0 * didFinishNavigationでは、ログが出てこない

原因

Sophos!!! なぜ、器用にiOS 9では動いてくれるか。 自分の半日が.......orz

I was developing some app using WKWebView and the properly-set webView did not load anything only on iOS 8 simulator, the iOS 9 was fine.

The webview's "estimatedProgress" was 1.0 from the beginning and there was no log shown in "didFinishNavigation" callback.

After a half day of my struggle I found out that Sophos was behind the scene.

If you are facing the same issue and ended up here, I suggest you turning off everything on Sophos and give it a try again!

Swift - UIStatusBar + UINavigationBarの上にCustomのUIViewやUILabelを追加する方法

Swift

単純にaddSubviewできない問題

カスタムのAlertや通知を表示させたいとき、UIStatusBarやUINavigationBarの上に追加したくなりますよね。 しかし、単純にaddSubviewしてもうまくいかない。 時刻は表示されるし、NavigationBarのbuttonは反応するし、大変…。

解決方法

  1. カスタムのUIWindowを作る
  2. その上にViewControllerを置く
  3. またその上にLabelを置く

イメージ

  • 真ん中の黄色い四角を押すと…カスタムWindowが表示される

  • f:id:pychef:20151027223355p:plain:w150

  • f:id:pychef:20151027223402p:plain:w150

コード

// 通知っぽい動きはUIViewのanimate~メソッドでカスタマイズしてください
// てきとうにadditionalWindowを宣言しておいた上で…


    private func setupCustomAlertWindow(){
        self.additionalWindow = UIWindow()
        self.additionalWindow.frame = CGRectMake(0,0,self.view.bounds.width,66)
        self.additionalWindow.clipsToBounds = true
        self.additionalWindow.windowLevel = UIWindowLevelAlert
        
        let additionalLabel = UILabel()
        additionalLabel.frame = self.additionalWindow.frame
        additionalLabel.backgroundColor = UIColor.clearColor()
        additionalLabel.text = "some kinda alert"
        additionalLabel.textColor = UIColor.grayColor()
        additionalLabel.textAlignment = NSTextAlignment.Center
        additionalLabel.userInteractionEnabled = true
        
        //tap検知したければ以下の2行追加
        let tapGesture = UITapGestureRecognizer(target: self, action:"didTapCustomAlert:")
        additionalLabel.addGestureRecognizer(tapGesture)
        
        // ViewControllerにより、画面のローテーションを検知できる iOS8以上
        let additionalViewController = UIViewController()
        additionalViewController.view.backgroundColor = UIColor.blueColor()
        additionalViewController.view.frame = self.additionalWindow.bounds
        additionalViewController.view.addSubview(additionalLabel)
        
        self.additionalWindow.rootViewController = additionalViewController
        self.additionalWindow.makeKeyAndVisible()
    }

カスタムのUIWindowを消したいときはnilを入れると消えます。 removeFromSuperview的なメソッドは今のところない模様。

self.additionalWindow = nil

Exercise 2.2 isSortedの解答 | 『Scala関数型デザイン&プログラミング』

Scala

Scala関数型デザイン&プログラミング』のEXERCISE 2.2の自己流の解答です。

自己流

object Exercise {
  def main(args: Array[String]){
    println(isSorted(Array(1,2,3,4,5), (x:Int, y:Int)=>{x<=y})) //メモ1
  }

  def isSorted[A](arr: Array[A], gt:(A, A)=>Boolean): Boolean = {
    @annotation.tailrec
    def loop(n: Int): Boolean = {
      if(arr.length-1==n) true //メモ2
      else if(gt(arr(n), arr(n+1))) loop(n+1) //メモ3
      else false //メモ4
    }
    loop(0)
  }
}

考え方メモ

  1. 比較関数の条件を考える。Array(1,2,3,5,4)はソートされているとはいえない。Array(1,2,3,4,5)Array(1,2,2,3,4)はソートされていると言える。
  2. loopメソッドのtrue停止条件を考える。カウンターの役割を果たすnが、最後の要素arr.length-1に到達できたら各要素はソートされていると言える。
  3. loopメソッドのループを考える。arr(n)arr(n+1)を比較して、1.の考え(gt)を満たしているか判定する。
  4. それ以外は、条件を満たしていないのでfalseと判定。

参考:オフィシャル流

オフィシャルグループのコードとは違います。 きっとgtに渡している比較関数が違うから、違うのでしょう。 どんなgtを渡しているんだろう? github.com

所感

再帰の考え方がいまいちつかめず苦戦。 いかに自分がいままで用意されてきた関数やメソッドで楽をしてきたか実感。 まだまだ修行が足りぬ。

便利なUnzipメソッド(Scala)

Scala

unzipは、複数のペアからなる1つMapや、Listを2つのリストに分割できる便利なメソッド

以下の例では、idのList[Int]と、namesのList[String]がリターンされる。

val beatles = Map(1 ->"John Lennon", 2 ->"George Harrison", 3 ->"Paul McCartney", 4 ->"Ringo Starr")
val (ids, names) = beatles.unzip 

/*
=>
ids: scala.collection.immutable.Iterable[Int] = List(1, 2, 3, 4)
names: scala.collection.immutable.Iterable[String] = List(John Lennon, George Harrison, Paul McCartney, Ringo Starr)
*/

@annotation.tailrec

Scala

"Functional Programming in Scala"を読み始めて、知らない概念ばかりでフルボッコにされている。

Scalaには、便利な@annotationがあることを学ぶ。
@を使うところとかObjective-Cコンパイラディレクティブと同じ。

例えば、関数がTail Recursiveにコーディングされているかを事前に確認したい場合、"@annotation.tailrec"を追記する。
スタックオーバーフローを発生させかねない劣悪なコードをコンパイルエラーで返してくれる。
ちなみに、IntelliJ IDEA 14ではわざわざPlayを押さなくても、エラーを赤ペンを入れてくれて便利。

  def factorial(n: Int): Int = {
    @annotation.tailrec
    def loop(n: Int, acc: Int): Int = {
      if(n<=0) acc
      else loop(n-1, n*acc)
    }
    loop(n,1)
  }

SwiftでStoryboardを使わずにナビゲーションバーとタブバーを設置する

Swift

↓や「ミュージック」アプリのように画面上にNavigationBar、画面下にTabBarを置く方法です。他にも効率的なやり方があったらぜひ教えてほしいです!

f:id:pychef:20150215195554p:plain

  • AppDelegate
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        window = UIWindow(frame: UIScreen.mainScreen().bounds)
        
        //2つViewControllerを用意
        var mainViewController = MainViewController()
        var secondViewController = SecondViewController()
        
        mainViewController.title = "first"
        secondViewController.title = "second"
        
        var navigationController1 = UINavigationController(rootViewController: mainViewController)
        var navigationController2 = UINavigationController(rootViewController: secondViewController)
        
        //2つのViewControllerをArrayでまとめます
        var tabs = [navigationController1, navigationController2]
        
        var tabBarController = UITabBarController()
        tabBarController.viewControllers = tabs
        
        window?.rootViewController = tabBarController
        window?.makeKeyAndVisible()
        return true
    }

Swiftでステータスバー、ナビゲーションバー、タブバー、それ以外の高さを取得する

Swift
  • いきなり余談

iOSオールスターズ勉強会」に参加してきました!


「iOSオールスターズ勉強会」に参加してきました #dotsios - Qiita

すべてのサンプルコードがSwiftで書かれていた点に何より驚きました(『let UIWebView as WKWebView』ではObjC先輩の力を借りる都合上、登場していましたが)。
さすがにこれはマズイと感じまして、プライベートではSwiftに乗り換えることにしました。

  • さて本題

さて、そんな感じで今日はSwift1日目。
今回は下図の青いViewサイズを取得する方法を考えてみました。
f:id:pychef:20150215195554p:plain

すべてのViewControllerにStatusBar, NavigationBar, TabBarが存在すると仮定し、AppDelegateにstatusBarHeight, navBarHeight, tabBarHeight, availableHeightの4つを用意してあげます。

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    var statusBarHeight:CGFloat? 
    var navBarHeight :CGFloat?
    var tabBarHeight :CGFloat?
    var availableViewHeight :CGFloat? //self.view.frame.size.heightからstatusBarHeight,navbarHeight, tabbarHeightを引いたもの


次に一番最初に呼び出されるrootViewControllerで以下のようなメソッドを用意し、viewDidLoad()時に呼び出してあげます。

func calculateHeights() {
        var ap:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
        ap.statusBarHeight = UIApplication.sharedApplication().statusBarFrame.height
        ap.navBarHeight = self.navigationController!.navigationBar.frame.size.height
        ap.tabBarHeight = self.tabBarController!.tabBar.frame.size.height
        ap.availableViewHeight = self.view.frame.size.height-ap.statusBarHeight!-ap.navBarHeight!-ap.tabBarHeight!
    }

これにより一度RootViewControllerでサイズをセットしてあげてるので、他のViewControllerでも下記のように活用できます。

var mainView = UIView()
var ap:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
mainView.frame = CGRectMake(0, ap.statusBarHeight!+ap.navBarHeight!, self.view.frame.size.width, ap.availableViewHeight!)
mainView.backgroundColor = UIColor.blueColor();
self.view.addSubview(mainView)

以上

追記

Xcode 6.3 betaにしたところ上の書き方ではエラーがでました。
下の書き方で対応あれ。

var ap:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate