swift UIManagedDocument エラー解決

UIManagedDocument.はiCloudに保存するときに利用するクラス。 Icloudをcoredataに保存することはできない。 アップルの仕様変更 f:id:happy_teeth_ago:20181017201556p:plain

アップルは ・「iCloud 上に構築したCoreDataをキー値やCloudKitを使って共有する機能がドロップされる」と言っている。 ・「アプリの(ローカル)CoreDataがドロップされる」と言っているのではないので、MrSurveyには影響はない。  測量くんはアプリのCoreDataをMrSurveyDocファイル内に書き込んで、単にファイルをiCloudで共有している。

では、読み込むときの実装は? 先にcoredata

ナビゲーションメニュー,HTML,CSS

ナビゲーションメニュー、HTML,CSSだけどきちんとまとめておく。 f:id:happy_teeth_ago:20181016191228p:plain

  <nav class="globalNavi">
        <ul>
            <li><a href="index.html">HOME</a></li>
            <li><a href="about.html">コンドミニアム紹介</a></li>
            <li><a href="access.html">アクセス</a></li>
            <li><a href="contact.html">お問い合わせ</a></li>
        </ul>
    </nav>

navタグで囲む

その配下にulとliタグ

CSS

.globalNavi {
  background: url("../images/gnavi_bg.png") repeat-x left top;//画像へのパス
  margin-bottom: 10px;
  border-top: 1px solid #fff; }
  .globalNavi ul {
    width: 1000px; //全体の幅
    margin-right: auto; //これで中央揃え
    margin-left: auto;  //これで中央揃え
    *zoom: 1;
    height: 67px; }
    .globalNavi ul:before, .globalNavi ul:after {
      display: table; //天地揃えたり、いろいろ便利
      content: "";
      line-height: 0; }

    .globalNavi ul:after { //これしておかないと後続の表示が崩れます。
      clear: both; }

    .globalNavi ul li {
      float: left; //左揃え
      width: 250px; //一つ一つのボタンサイズ
      height: 63px;
      margin: 3px 0 0 0;
      border-left: 1px solid #ccc;
      border-right: 1px solid #fff;
      vertical-align: middle;
      text-align: center; //普通真ん中に揃えます
      overflow: hidden; } //はみ出たものは無視しないと、形くずれます。

      .globalNavi ul li a:hover img { //マウスが乗っかったときの処理
        opacity: 0.8; //上記のようにボタンの上に来ると薄く表示
        filter: alpha(opacity=0.8);
        -ms-filter: "alpha( opacity=$alpha )"; }

      .globalNavi ul li:last-child {//ボタンの左に縦の棒の線が入っているので、最後のボタンにはcssで追加
        border-right: 1px solid #ccc; }

      .globalNavi ul li a {
        color: #333;
        text-decoration: none;
        padding: 22px 0px;
        display: block;
        font-weight: bold;
        text-align: center; }
        .globalNavi ul li a:hover {
          background-color: rgba(255, 255, 255, 0.8); }

CSSもきちんとかけないといけない。

参考にした本 この本おすすめです。

https://www.amazon.co.jp/WordPress-%E4%BB%95%E4%BA%8B%E3%81%AE%E7%8F%BE%E5%A0%B4%E3%81%A7%E3%82%B5%E3%83%83%E3%81%A8%E4%BD%BF%E3%81%88%E3%82%8B-%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E6%95%99%E7%A7%91%E6%9B%B8-Web%E3%83%87%E3%82%B6%E3%82%A4%E3%83%8A%E3%83%BC%E9%A4%8A%E6%88%90%E8%AC%9B%E5%BA%A7-%E4%B8%AD%E5%B3%B6-%E7%9C%9F%E6%B4%8B/dp/4774173800/ref=sr_1_3?ie=UTF8&qid=1539685506&sr=8-3&keywords=wordpress

Swift 状態に応じてbutton の表示を切り替え、ローカライズも

f:id:happy_teeth_ago:20181014114219p:plain

このnameボタンは状態を持っている。

それを状態に応じて表示を切り分ける。

接続はこう

@IBOutlet weak var uiNameSorter: UIButton!
   /// 複合構成点データをロードする
    private func fetchPolyNodes() {
        let polyTypes = [PolyType.MapLot,PolyType.MapRoute]
        ofPolyNodes.disconnect()
        ofPolyNodes.fetch(CdPolyNode.fetchRequestFor(
            ofPolyNodes.previousRequest,polyTypes,typeNumAsc: !uiNameSorter.isSelected))
      //ここで値をセット
        uiNameSorter.setTitle("name↑", for: .selected)
        uiNameSorter.title(for: .selected)
    }

しかしこれでは、英語以外の言語でもすべて"name↑"と表示されてしまう。 よってメッセージの定数を宣言し、そこにセットするだけ

NSLocalizedStringを利用する。

   let str: String = NSLocalizedString("MsrMsgUINameSorter", comment: "")
        uiNameSorter.setTitle( str, for: .selected)
        uiNameSorter.title(for: .selected)

commentはキーとバリューには関係ないので、なしで良い。必要があれば記載する そして Localizable.strings(Japanese)にキーとバリューを記載する(ちなみにbaseは必ず英語) f:id:happy_teeth_ago:20181015110311p:plain

//Base
"MsrMsgUINameSorter" = "name↑";
//Japanese
"MsrMsgUINameSorter" = "名前↑";

これで完成!

通常のボタンタイトルのセット

 button.setTitle("ボタンおしてね!", for: .normal) // ボタンのタイトル

関数定義はこれ

f:id:happy_teeth_ago:20181014115955p:plain

余談ですが、日本人のプログラム能力が低いのは、リファレンスを読まないからと、聞いたのでなるべくリファレンスを参照することにしました。ブログ読んで、エラーがなくなったら良しとしているから、米国と差がつくのだそうです。

simplearchitect.hatenablog.com

通常はボタンにsetTitleするだけ。

UIControl.Stateにはつぎの状態を保持できる。

f:id:happy_teeth_ago:20181014120501p:plain

ソースに戻ります。

表示のたびにfetchをかける

ボタンの状態を取得するために、フェッチ用の関数を作る。

fetchRequestForのところで呼び出している

   static func fetchRequestFor(
        _ request: NSFetchRequest<CdPolyNode>?,
        _ types: [PolyType],
        typeNumAsc: Bool = true
//CdPolyNodeはDB
        ) -> NSFetchRequest<CdPolyNode> {
        let predicate = buildPredicate(types, nil, nil)
        return fetchRequestFor(request, predicate, typeNumAsc:typeNumAsc)
    }

CdPolyNodeの拡張

NSPredicateを返す。今回は他にも返したい値があるので、関数を作成。
 static func buildPredicate(_ types: [PolyType], _ format:String?, _ args:[Any]?) -> NSPredicate {
        var boundArgs:[Any] = [types.map({$0.rawValue})]
        var boundFormat = "\(#keyPath(CdPolyNode.type)) IN %@"
        if let _format = format , !_format.isEmpty {
            if let _args = args { boundArgs.append(contentsOf: _args)}
            boundFormat = boundFormat + " AND \(_format)"
        }
        return NSPredicate(format: boundFormat, argumentArray: boundArgs)
    }

ローカライズはxcode10.0 より全く新しくなったので、これを見ておいたほうが良い。 12分位から、実装の説明がある。

developer.apple.com

忘備録のため、かなりわかりにくい説明となっている点、ご了承ください。

Swift4 テキストフィールドをキーボードに隠れないように変更

基本的な考え

スクロールビューをStoryBoardへ配置、IBOutlet 接続

まず入力されたテキストフィールドを取得(座標値)

Notificationにより、画面サイズ、キーボードのサイズを取得

テキストフィールドの位置が、キーボドサイズより小さければ、上方向へスクロール (contentOffset.y)

入力後はスクロールを0に戻す

以上の流れです。

では実装

テキストフィールドに入力開始時に呼ばれるデリゲートメソッド

ここにはメンバ変数に入力されたテキストフィールドを渡しているだけ。 どのテキストフィールドを呼ばれても、ここが呼ばれる。

引数がtextFieldで、編集に入ったテキストフィールドをメンバにわたす.

それをメンバ変数に持っておく。座標をメンバに持っておく

呼び出し時

  func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
        //メンバ(座標保持)に現在入力されている textFieldを渡す。
        txtActiveField = textField
        return true
    }

上記で詰め込んだメンバ変数 ただのUITextField型で良い

  //メンバ
    var txtActiveField:UITextField?

ここで画面サイズを取得して、画面の一番上をget マージンを8pxにしてセットしている

//この関数名は適当で良い、下記のセレクターで渡している。
    @objc func handleKeyboardWillShowNotification(notification: Notification) {
        //userInfoにはキーボードの位置とサイズが、辞書型で入っている
        let userInfo = notification.userInfo!
        //userInfoからキーボードのフレームサイズを取得
        let keyboardScreenEndFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
        //myBoudSize= 画面サイズ
        let myBoudSize:CGSize = UIScreen.main.bounds.size
        
        //origin.yはテキストフィールドの左上が取得できる 画面の座標系は左上が0.0 右下へ大きくなる
        let textLimit = txtActiveField!.frame.origin.y + txtActiveField!.frame.height + 8.0
        let kbdLmit = myBoudSize.height - keyboardScreenEndFrame.size.height
        if textLimit >= kbdLmit{
            scrollView.contentOffset.y = textLimit - kbdLmit
        }
        
    }

scrollViewは画面に配置しているもの

  @IBOutlet weak var scrollView: UIScrollView!

Notificationの構造体に移行されたようだ

またuserinfo はハッシュ

public struct Notification : ReferenceConvertible, Equatable, Hashable {

    public typealias ReferenceType = NSNotification

    /// Storage for values or objects related to this notification.
    public var userInfo: [AnyHashable : Any]?

UIKeyboardFrameEndUserInfoKeyはアップルのグローバル変数

スクリーン座標でキーボードの終了フレーム矩形を識別するCGRectを含むNSValueオブジェクトのキー。フレームの四角形は、デバイスの現在の向きを反映しています。

上記関数をセレクターで渡す。

画面呼び出すたびに呼ばれるviewWillAppearにセット

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(true)
        
        let notification = NotificationCenter.default
        //addObserverにセットすることで監視してくれる
        notification.addObserver(self, selector: #selector(handleKeyboardWillShowNotification(notification:)) , name: .UIKeyboardWillShow, object: nil)
        
    }

addObserverの関数定義

func addObserver(_ observer: Any, 
        selector aSelector: Selector, 
            name aName: NSNotification.Name?, 
          object anObject: Any?)

observer :登録するオブジェクト

ここはこのクラスで宣言しているのでself

aSelector :通知を送付するメソッドを指定する。そのメソッドは一つだけ引数(オブジェクト)を保つ必要がある。

selectorの後に(関数名(引数))

aName :オブザーバーを登録する通知の名前。 .UIKeyboardWillShow

anObject:オブザーバが受信したい通知を持つオブジェクト。つまり、この送信者によって送信された通知のみがオブザーバに配信される

    //閉じるときの処理 アップルのデリゲートメソッド 自動的に呼ばれる
    func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
        self.view.endEditing(true)
        return true
    }
    
    //閉じるときの処理 縦スクロールの値に0を入れる
    func handleKeyboardWillHideNotification(notification: Notification) {
        scrollView.contentOffset.y = 0
    }
    

PHP -> アロー演算子について

PHPの ->見慣れない、アロー演算子についてまとめます。

一言で言うと、オブジェクトのプロパティーにアクセスしているだけ。

Rubyの . (ドット)と同じイメージ。

作ったオブジェクトのプパティーにアクセスする。

まずRubyで書く。

class Car

    attr_accessor :color 
    attr_accessor :name
    # インスタンス作るときには、一番始めに初めにinitializeが呼ばれます。
    def initialize(color, name)
        @color = color
        @name = name
    end
    
    #車を走らせるための機能をまとめた関数の部分(クラス側)

    def run()
        print "#{self.name}の車の色は、#{self.color}です。"
    end
end

myCar =  Car.new('blue', 'civic')

#車を走らせる
print myCar.run

結果

=>civicの車の色は、blue

PHPはこう

<?php
$myCar = new Car();

// 車を表示
$myCar->run();

class Car
{
    public $color = "blue";
    public $name = "civic";

    // 車の表示をまとめた関数の部分(クラス側)
    public function run(){
        print "{$this->name}の車の色は{$this->color}です";

    }
}
?>

参考サイトです。

lovee7.blog.fc2.com

Swift UIButton タイトル文字の余白設定 継承について

UIButton のタイトル文字にパディングを設定する。

実現したいことはこれ。

これがStoryBoad上の表示

f:id:happy_teeth_ago:20181001173640p:plain:w300

これが、iPhone上の表示。ビルド時には、このように表示したい。

f:id:happy_teeth_ago:20181001172518p:plain:w300

参考にしたサイトには下記のように書いてある。

ボタンのサイズに併せて、titleLabelをフィットさせたい時は以下の1行で済みます。

self.myOutlet_answerBtn1.titleLabel.adjustsFontSizeToFitWidth = YES;

ボタンのインスタンスに対して、プロパティを設定している。 しかし、すべてのボタンに対して設定するのは面倒である。

それでUIButtonを継承したクラスを作成し、それを利用することにする。

class MsTitledButton: UIButton {
    /// contentRect に関する Title label の 上下 margin
   //これはただの上方向への移動  
   private static let MARGIN_VRT: CGFloat = 15.0
    
    override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
    
        let tr = super.titleRect(forContentRect: contentRect)
        return CGRect(x:tr.origin.x,
                      y:contentRect.minY + MsTitledButton.MARGIN_VRT,
                      width:tr.width ,height:tr.height)
    }
    //ここがタイトル文字のパディング。まずタイトルの幅を決めて上げる。それに対してadjustsFontSizeToFitWidthをセット
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        // 英文がはみ出ないように、サイズに合わせてフィットさせる
        titleEdgeInsets = UIEdgeInsets(top: 0.0, left: 10.0, bottom: 0.0, right: 15.0)
        titleLabel!.adjustsFontSizeToFitWidth = true
    }

ここでのポイントは、UIButton のクラスをオーバーライドするときに、initメソッドを呼ぶこと。 そうすることにより、UIButtonのプロパティ-にアクセスできる。

このメソッドは、アップルが用意しているもので、変更不可。いつも定形。よって覚えるしか無い。

required init?(coder aDecoder: NSCoder) {

super.init(coder: aDecoder)

こうすることにより、StoryBoardで接続するときに、クラスを選択するだけで自動でセットされる。

IBOutlet接続時に、UIButton を継承したクラスは表示される。

f:id:happy_teeth_ago:20181001173524p:plain

これが継承である。

説明するより、実際に目的をもって使ってみて、なれるほうが大切だと思う。