swiftのイニシャライザまわりでコンパイルエラーになることが多かったのでいろいろ試してみた

swiftのイニシャライザまわりでコンパイルエラーになることが多くてちょっと調べてみた。
いろいろ実験しているが本当は原理を知らないといけないと思う。
でもうんこエンジニアなので原理を理解できない

§ まとめ

最初にまとめを書いておく

定数の定義 → super.init() → メソッドを呼ぶ

の順番で呼ぶと良い

§ 実験

継承してないパターン

■ initからメソッド呼び出し

これは普通に通る

import Foundation
class SampleUseCase {
    init() {
        bind()
    }
    
    func bind() {
       print("bind")
    }
}

■ let で変数を設定した場合

let の変数が全部初期化されたあとはメソッドを呼べる

=>これは問題なく通る

f:id:konohazukux:20180606164124p:plain

■ let変数の前にメソッドをcall

Use of 'self' in method call 'bind' before all stored properties are initialized
「全てのプロパティーが初期化される前にメソッドをcallするときはselfを使え」とのこと

f:id:konohazukux:20180606164317p:plain

■ selfをつけてみる

=>selfをつけても結果は同じ。。? f:id:konohazukux:20180606164542p:plain

継承しているパターン

■ 継承してサブクラスにした場合

=> 先にsuper.init を呼べとのこと

f:id:konohazukux:20180606164832p:plain

■ メソッドを呼ぶ前にsuper.initを呼ぶ。

=> これはOK

f:id:konohazukux:20180606165051p:plain

■ let定数の前にsuper.initをよんでみた。

=> これはダメとのこと

f:id:konohazukux:20180606165145p:plain

■ メソッドよびだしの後にsuper.initを呼んでみた

f:id:konohazukux:20180606165336p:plain

=> ダメ

iOS テーブルのセルがタブにめり込む問題

下記の画像のようにテーブルビューの一番下のセルがタブにめり込んで出てこないのはなんでだろうと思って調べました。

f:id:konohazukux:20180527144143g:plain

次の3つのパラメーターの設定方法に問題があったみたい。

■ isTranslucentの設定

 Translucent は 半透明とのこと。
 ナビバーやタブバーに設定するもので背景を半透明に透過するかを指定する。 

navigationController?.navigationBar.isTranslucent = false // ナビバーを半透明にしない   
tabBarController?.tabBar.isTranslucent = false // タブバーを半透明にしない

■ extendedLayoutIncludesOpaqueBars の設定

 extended Layout   Includes  OpaqueBars   
 拡張   レイアウト  含める   不透明な部分  

 不透明な部分を拡張レイアウトに含めるかどうか

extendedLayoutIncludesOpaqueBars = true

の場合はナビバーやタブバーを半透明にしなかった場合にもナビバー、タブバーの部分を拡張レイアウトに含める。

■ edgesForExtendedLayout の設定

    edges  For     Extended  Layout      
    端っこ のための     拡張           レイアウト  

どこを拡張レイアウト用の端とするか。
edgesForExtendedLayout = .all

つまり

  • タブバーを半透明にしないで、
  • 不透明な部分も拡張レイアウトに含めて、
  • 拡張レイアウトを下端にも適用させる。

といった設定になっている場合にタブの下にセルがめり込んで最後のセルが出てこないといった問題が発生する。

問題の発生するコードを掲載します。

//
//  SampleViewController.swift
//

import UIKit

class SampleViewController: UIViewController {
    
    let sampleDatas = ["1","2","3","4","5","6","7","8","9","0","1","2","3","4","5","6","7","8","9","0"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        title = "タブ1"

        // 1. ナビバー、タブバーを半透明にするかの設定
        navigationController?.navigationBar.isTranslucent = false
        tabBarController?.tabBar.isTranslucent = false
        
        // 2. 半透明ではない部分も拡張レイアウトに含めるかの設定
        extendedLayoutIncludesOpaqueBars = true
        
        // 3. どの部分が拡張レイアウトの対象となるか
        edgesForExtendedLayout = .bottom
        
        let tableView = UITableView()
        tableView.dataSource = self
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")

        view.addSubview(tableView)
        
        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        tableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        tableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    }
}

extension SampleViewController: UITableViewDataSource {
    public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return sampleDatas.count
    }
    public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
       let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = sampleDatas[indexPath.row]
        if indexPath.row % 2 == 0 {
            cell.backgroundColor = UIColor(red: 0.5, green: 0.5, blue: 1, alpha: 1)
        } else {
            cell.backgroundColor = UIColor(red: 0.5, green: 1, blue: 0.5, alpha: 1)
        }
        return cell
    }
}

IMP型について調べてみる

IMP型について調べてみようかと思います。

とりあえずよくわからなかったので実装してみます。

ARCだとちょっと工夫が必要とのことでMRCで実装します。


ExampleObject.h

#import <Foundation/Foundation.h>
@interface ExampleObject : NSObject
-(void)exec;
@end

ExampleObject.m

#import "ExampleObject.h"
#import <objc/Object.h>

@interface SampleClass : NSObject
-(void)sampleMethod;
@end

@implementation SampleClass
-(void)sampleMethod
{
    NSLog(@"sampleMethodが実行されたー");
}
@end

@implementation ExampleObject
-(void)exec
{
    id obj = [SampleClass new];
    SEL method = @selector(sampleMethod);
    IMP func = [obj methodForSelector:method];
    func();
}
@end


これを下記の通り実行すると

    ExampleObject *exampleObject = [[ExampleObject alloc] init];
    [exampleObject exec];


実行結果は
2015-03-22 15:50:40.383 Example[24294:641518] sampleMethodが実行されたー
となります