あたも技術ブログ

セットジャパンコーポレーションの社員が運営しています。

とりあえずこれだけ覚えておこう!フォトショのショートカット

 f:id:atamo_dev:20170912194813j:plain

Photoshopでやりたい作業って、分類わけするとだいたい下記みたいな感じになると思います。(もっとあるかもしれませんが)

 

・「画像の一部を消し飛ばす or 増やす」
・「何か描く」
・「サイズを変更する」
・「明るさや色を変更する」
・「効果を加える」
・「AとBを合成する」

 

それぞれどの動作を行うにしても、[どのレイヤー]の[どの部分(選択範囲)]でそれを行うのか必ず決めてから行います。
このことから、Photoshopの操作は、[選択範囲]と[レイヤー]のコントロールが下敷きになっていると言ってもいいかもしれません。

 

というわけで

 

 Photoshopのショートカットキーメンドクセーって人は最低下記のショートカットキーだけは覚えておきましょう。 

Photoshopのバージョンは、Adobe CC2017です。

 

 ・全選択
 Ctrl + A

 

・選択範囲の反転

 Ctrl + Shift + i

 

・選択範囲の解除
 Ctrl + d

 

・選択範囲をコピーしたレイヤーの作成(選択範囲がないときはレイヤーの選んでいるレイヤーを丸ごと複製する)
 Ctrl + j

 

・新規レイヤー作成
 Ctrl + Alt + Shift + n

 

・塗りつぶし(塗りつぶしダイアログの召喚 → そのままEnterで秒速塗りつぶしコンボが完成します。これがあればバケツなんていらない。一回目だけは内容を選ぶ必要あり)
 Shift + F5

 

・画像解像度
 Ctrl + Alt + i

 

・キャンバスサイズ
 Ctrl + Alt + c

 

・変形
 Ctrl + t

 

いかがでしたでしょうか?

とりあえずこんだけ覚えておけば大丈夫ですん。ショートカットキーをまったく使わない時に比べると作業スピードは倍加しますよ。

 

今回はこんな感じで。また近いうちにお会いしましょう。

最後まで読んでいただきありがとうございました。

 

By SetJapanCorporation,Inc. Designer : すんすん。

【C#】Windowsフォーム アプリケーションのグラデーション背景と枠線を表示できるパネルユーザコントロール

 久しぶりのWindowsフォーム アプリケーションのユーザコントロールネタです。
 WPFだとコントロールに枠線やグラデーションを行うのは容易ですが、Windowsフォーム アプリケーションだと面倒なことこの上ないです。
 Panelを継承し、OnPaintをoverrideして自力で背景と枠線を描画してやっと出来るっていう…。

 グラデーション背景と枠線を表示できるパネルユーザコントロールの実装コードです。

namespace GradationPanelSample
{
  partial class GradationPanel
  {
    /// <summary> 
    /// 必要なデザイナー変数です。
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary> 
    /// 使用中のリソースをすべてクリーンアップします。
    /// </summary>
    /// <param name="disposing">マネージ リソースを破棄する場合は true を指定し、その他の場合は false を指定します。</param>
    protected override void Dispose(bool disposing)
    {
      if (disposing && (components != null))
      {
        components.Dispose();
      }
      base.Dispose(disposing);
    }

    #region コンポーネント デザイナーで生成されたコード

    /// <summary> 
    /// デザイナー サポートに必要なメソッドです。このメソッドの内容を 
    /// コード エディターで変更しないでください。
    /// </summary>
    private void InitializeComponent()
    {
      components = new System.ComponentModel.Container();
    }

    #endregion
  }
}
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace GradationPanelSample
{
  /// <summary>
  /// グラデーションパネルユーザコントロール
  /// </summary>
  public partial class GradationPanel : Panel
  {
    #region プロパティ
    /// <summary>
    /// コントロールの境界線のスタイル
    /// </summary>
    /// <remarks>PanelのデフォルトプロパティであるBorderStyleを隠蔽している。</remarks>
    [CategoryAttribute("表示")]
    [DescriptionAttribute("コントロールの境界線スタイルを取得または設定します。")]
    [BrowsableAttribute(false)]
    public new BorderStyle BorderStyle { get; set; } = BorderStyle.None;

    /// <summary>
    /// コントロールの境界線の色
    /// </summary>
    [CategoryAttribute("表示")]
    [DescriptionAttribute("コントロールの境界線の色を取得または設定します。")]
    [BrowsableAttribute(true)]
    public Color BorderColor { get; set; } = Color.Black;

    /// <summary>
    /// コントロールの境界線の太さ
    /// </summary>
    [CategoryAttribute("表示")]
    [DescriptionAttribute("コントロールの境界線の太さを取得または設定します。0を設定した場合は枠線は描画されません。")]
    [BrowsableAttribute(true)]
    [DefaultValue(0)]
    public int BorderThickness { get; set; } = 0;

    /// <summary>
    /// コントロールのグラデーション開始色
    /// </summary>
    [CategoryAttribute("表示")]
    [DescriptionAttribute("コントロールのグラデーション開始色を取得または設定します。")]
    [BrowsableAttribute(true)]
    public Color StartColor { get; set; } = SystemColors.Control;

    /// <summary>
    /// コントロールのグラデーション終了色
    /// </summary>
    [CategoryAttribute("表示")]
    [DescriptionAttribute("コントロールのグラデーション終了色を取得または設定します。")]
    [BrowsableAttribute(true)]
    public Color EndColor { get; set; } = SystemColors.Control;

    /// <summary>
    /// コントロールのグラデーションモード
    /// </summary>
    [CategoryAttribute("表示")]
    [DescriptionAttribute("コントロールのグラデーションのモードを取得または設定します。")]
    [BrowsableAttribute(true)]
    public LinearGradientMode GradientMode { get; set; } = LinearGradientMode.Vertical;
    #endregion

    #region コンストラクタ
    /// <summary>
    /// クラスの新しいインスタンスを初期化します。
    /// </summary>
    public GradationPanel()
    {
      InitializeComponent();
    }
    #endregion

    #region protectedメソッド
    /// <summary>
    /// 描画処理
    /// </summary>
    /// <param name="pevent">Paintイベント引数</param>
    protected override void OnPaint(PaintEventArgs pevent)
    {
      using (var graphics = pevent.Graphics)
      {
        var borderThickness = GetHarfBorderThickness();
        var x = borderThickness;
        var y = borderThickness;
        var width = 0 < borderThickness ? Width - (borderThickness * 2) : Width;
        var height = 0 < borderThickness ? Height - (borderThickness * 2) : Height;

        // 幅と高さが0より小さい場合は、最小値の1を設定する
        if (width <= 0) { width = 1; }
        if (height <= 0) { height = 1; }

        // 算出した幅と高さがコントロールの領域の1/2より大きい場合は、値を設定し直す
        if ((Width / 2) < borderThickness)
        {
          borderThickness = (int)Math.Floor(Width / 2.0F);
        }
        if ((Height / 2) < borderThickness)
        {
          borderThickness = (int)Math.Floor(Height / 2.0F);
        }

        // 背景の描画領域を指定する
        var rectangle = new Rectangle(x, y, width, height);
        using (var linearGradientBrush = new LinearGradientBrush(new Rectangle(x, y, width, height), StartColor, EndColor, GradientMode))
        {
          // グラデーションブラシを生成し描画する
          graphics.FillRectangle(linearGradientBrush, rectangle);
        }

        if (0 < BorderThickness)
        {
          using (var pen = new Pen(BorderColor, BorderThickness))
          {
            graphics.DrawRectangle(pen, 0 + borderThickness, 0 + borderThickness, width, height);
          }
        }
      }
    }
    #endregion

    #region privateメソッド
    /// <summary>
    /// 枠線の太さの1/2の値を取得します。
    /// </summary>
    /// <returns>枠線の太さの1/2の値</returns>
    private int GetHarfBorderThickness()
    {
      return (int)System.Math.Floor((double)(BorderThickness) / 2 + 0.5);
    }
    #endregion
  }
}

 枠線の太さの最小値と最大値を補正するように記述しています。頭が悪いのでもっと綺麗に書けそうですが、わたしの脳みそではこれで限界です。
 Windowsフォーム アプリケーションのユーザコントロールネタにまた戻ってきましたが、そろそろネタが無くなりそう。

【iOS】Alamofire + Himotokiでいい感じのAPIクライアントを作る

どうも、社内開発でiOSを担当してる朝倉です。

現在、夏期休業中ですが、そういえばブログ更新しないといけないなと思い出したので書きます。

Alamofire + HimotokiでAPIクライアントを作るということで、n番煎じだしもっといい方法がネット上にはゴロゴロある気がするのですが、 現状、(僕が)いい感じだと思っている実装を書いてみたいと思います。

導入

CocoaPodsでAlamofireとHimotokiを導入します。

「そんなの知ってるよ」とかCarthage派の人やSPM派の人は読み飛ばしてください。

ターミナルでプロジェクトディレクトリへ移動し、

pod init

Podfileが作成されるので以下の2行を追加します。

pod 'Alamofire', '~> 4.4'
pod 'Himotoki', '~> 3.0'

このようになればOKです。

target 'プロジェクト名' do
  use_frameworks!
  pod 'Alamofire', '~> 4.4'
  pod 'Himotoki', '~> 3.0'
end

Podfileを保存し、

pod install

これで、AlamofireとHimotokiがプロジェクトに追加されたので、プロジェクト名.xcworkspaceファイルを開きます。

APIクライアントを作る

今回は、GitHubAPIを使用します。 まずは共通の通信部分を作成します。

import Alamofire
import Himotoki

enum Result<T> {
    case Success(T)
    case Error(Error)
}

protocol APIRequest {
    var baseeUrl: String { get }
    var headerTemplate: [String : String] { get }
    
    associatedtype Response
    var path: String { get }
    var method: HTTPMethod { get }
    
    var parameters: [String : Any]? { get set }
    var headers: [String : String]? { get set }
    
    func response(from object: Any) throws -> Self.Response
    
}

extension APIRequest {
    var baseeUrl: String {
        return "https://api.github.com"
    }
    var headerTemplate: [String : String] {
        return ["X-Requested-With" : "XMLHttpRequest"]
    }
    var parameters: Any? {
        return nil
    }
    var headers: [String : String]? {
        return nil
    }
    
    func request(finished: @escaping (Result<Self.Response>)->Void) {
        let encoding = JSONEncoding.default
        var header = headerTemplate as Dictionary<String, String>
        headerTemplate.forEach() {
            header[$0.0] = $0.1
        }
        
        let encodedURLString = (baseeUrl + path).addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)
        
        Alamofire.request(encodedURLString!, method: method, parameters: parameters, encoding: encoding, headers: header).responseJSON { response in
            switch response.result {
            case .success(let value):
                print(value)
                do {
                let res = try self.response(from: value)
                    finished(Result.Success(res))
                } catch {
                    finished(Result.Error(error))
                }
            case .failure(let error):
                finished(Result<Self.Response>.Error(error))
            }
        }
    }
}

続いて、Decodableプロトコルを適応したモデルとAPIRequestプロトコルを適応したリクエストオブジェクトを作成していきます。

ユーザのリポジトリを取得する

import Himotoki
import Alamofire

struct Repository: Decodable {
    let fullName: String
    let ownerAvatarUrl: String
    let language: String?
    let url: String
    let htmlUrl: String
    
    static func decode(_ e: Extractor) throws -> Repository {
        return try Repository(
            fullName: e <| "full_name",
            ownerAvatarUrl: e <| ["owner", "avatar_url"],
            language: e <|? "language",
            url: e <| "url",
            htmlUrl: e <| "html_url"
        )
    }
}

struct  UserRepository: APIRequest {
    var headers: [String : String]? = nil
    var parameters: [String : Any]? = nil
    var userName: String
    
    var path: String {
        return "/users/\(self.userName)/repos"
    }
    var method: HTTPMethod {
        return .get
    }
    typealias Response = [Repository]
    
    init(userName: String) {
        self.userName = userName
    }
    
    func response(from object: Any) throws -> Response {
        return try decodeArray(object)
    }
}

今後、エンドポイントが増えた場合にはDecodableプロトコルを適応したレスポンスモデルとAPIRequestプロトコルを適応したリクエストオブジェクトを増やしていけばいいだけなのでお手軽です。

使い方

UserRepository(userName: "asashin227").request() { result in
    switch result {
    case .Success(let responce):
        print(responce)
    case .Error(let error):
        print(error.localizedDescription)
    }
}

ソース

とりあえずGitHubにあげたので参考にご利用ください。

github.com

メールってどうなってるのか考える

前回「名前解決」という不思議なワードを攻略したので
インターネット空間をどんな目印で動いてるか分かったかなと思います。

 今回はインターネットの利用の双璧「メール」について少し書いてみます。
インターネットの中というのは、それまで使われていた現実世界の概念をネットワークの世界に持ち込んだものが多いので、てっとり早く理解するには現実世界と比較するのが一番です。

 

さて、「メール」。読んで字のごとし「手紙」です。
日本語は便利なもので、「メール」「手紙」も、もとの意味は同じなのに表現を変えるだけで、いまや「メール」といえば「電子メール」を指すのが一般的になりました。

 「メール送っといて」といわれて、手紙書いて切手貼って郵便ポストへ・・・という人はかなりレアですよね。
だいたいはPCやスマホでメールを打って送信すると、しばらくすると相手のスマホなんかに届く。この間がどうなっているのか見てみようかと思います。

 

あなたがメールを送ると、メールサーバに送られます。これはポストに手紙を出すのに相当しますが、ここは簡単に想像できるとおもいます。
どこのメールサーバに送るかといえば、自分の契約しているプロバイダーとか、会社なら自社のメールサーバに送ることになり、これはメールソフトにあらかじめ初期設定とかで設定してあります。自分専用の窓口がある郵便局のようなイメージです。

 

その後、メールを受取ったサーバは、宛先アドレスから相手のメールサーバを探します。ここで、前回の名前解決が使われます。
相手のメールサーバがわかると、そのサーバへメールの転送が行われます。ちょうど、郵便局間で手紙が運ばれるのと同じですね。


・・・でもこれでは、サーバには到着しますが、スマホには来ないですよね?
郵便局に届いても自宅に届かないと手紙は読めません。

 

ここで登場するのが「プッシュ通信」という、いわば配達員と同じ動きをする機能です
サーバに到着したメールは、「サーバー側から」(ここがミソ)送信先の携帯端末などを探して、そこへメールを送り込みます。これは携帯端末とメールアドレスが1対1なのでできる芸当。主に携帯キャリア(d社とかa社とかs社とか・・・)などのメールで使われます。最近はWebブラウザでも同様の動きができるようになってます。

 

でも、携帯キャリアのメールアドレスじゃなくても、スマホにメール、きますよね?
これは実はメールが「来る」わけではなく「届く」といったほうが適当です。
「端末から」定期的だったり手動だったりでサーバーに「メールを取りに」いってます。メールがあれば、サーバからデータを引っ張ってくるので「プル通信」といわれます。この動きは、郵便局の私書箱へ届いている手紙を取りに行く、のと同じ働きになります。 

 

これ以外にもメール関係のキーワードとしては・・
・端末にメールをもってきて読むPOP3や、メールはサーバーに置いたまま、内容を読むIMAPなどという方式の違い。パソコンやプロバイダーのメールはPOP3、携帯など移動体のメールはIMAPがよく使われます
・セキュリティ対策、特にスパム送信対策のPOP before SMTPとか、SMTP Auth」という送信認証。実はもともとメール送信というのは認証なしで送れました。ですが、これではスパム送り放題ですので実装された方式です
・ほかにもセキュリティ対策で「サブミッションポート」だったり「暗号化」「フィルタリング」MIME」「HTMLメール」・・・

などなど、メールは昔からある、比較的単純な通信ですが、なかなか奥が深いです。

 

なお。
説明の都合上、かなり端折ったり、デフォルメしていますので
もっとメールの仕組みを知りたい人はSetJapanの門をたたいてみましょう。

 

【C#】Excelの取り扱いにClosedXMLを使用する

 今回はC#Excelを使用したい場合を考えたいと思います。2008年辺りまではCOMコンポーネントを使用してMicrosoft Excel 12.0 Object Libraryを参照し、COMオブジェクトの解放地獄でかなり苦しんでおられたのではないでしょうか。
 Office2007以降の場合、xlsx、xlsmファイルとなり内部的にはXML形式となりました。これによってCOMオブジェクトうを使用せずにExcelファイルを扱えるライブラリが色々公開されています。
 その中でClosedXMLをご紹介したいと思います。
 
1. Excelを扱うプロジェクトを作成します。
2. Visual Studioを起動し、「ツール」→「NuGet パッケージマネージャー」→「ソリューションの NuGet パッケージの管理」を選択します。
f:id:atamo_dev:20170719212412j:plain
3.「NuGet パッケージ管理ウィンドウ」で左のオンラインを選択します。
4. 右上オンラインの検索欄に「OpenXML」と入力し、検索を実行します。
f:id:atamo_dev:20170719212439j:plain
5. 表示された「DocumentFormat.OpenXml」を選択すると「インストール」ボタンが表示されていますので、「インストール」ボタンを押下し、指示に従ってインストールを行います。
6. 右上オンラインの検索欄に「ClosedXML」と入力し、検索を実行します。
f:id:atamo_dev:20170719212451j:plain
7. 表示された「ClosedXML」を選択すると「インストール」ボタンが表示されていますので、「インストール」ボタンを押下し、指示に従ってインストールを行います。

 これで前準備は完了しました。

github.comOpenXML SDK
github.comClosedXML


 以下Excelを扱ったサンプルクラスです。

using ClosedXML.Excel;
using System;
using System.IO;

namespace ExcelSample
{
  /// <summary>
  /// Excelの読み込みとワークシート、セルへのアクセスを行うクラス
  /// </summary>
  public class ExcelLoader : IDisposable
  {
    #region メンバ変数
    /// <summary>
    /// Excelのワークブック(2013以降のExcelを指定すること)
    /// </summary>
    private XLWorkbook _Workbook = null;
    #endregion

    #region プロパティ
    /// <summary>
    /// 全てのワークシートを取得します。
    /// </summary>
    public IXLWorksheets Worksheets
    {
      get
      {
        if (this._Workbook != null)
        {
          return this._Workbook.Worksheets;
        }
        else
        {
          return null;
        }
      }
    }
    #endregion

    #region コンストラクタ
    /// <summary>
    /// 新しいクラスのインスタンスを作成します。
    /// </summary>
    public ExcelLoader()
    {
    }

    /// <summary>
    /// 新しいクラスのインスタンスを作成します。
    /// </summary>
    /// <param name="path">Excelファイルのパス</param>
    public ExcelLoader(string path)
    {
      if (!string.IsNullOrEmpty(path) && File.Exists(path))
      {
        // ファイルパスが設定されているかつ、そのパスのファイルが存在する場合、ファイルを開く
        this._Workbook = new XLWorkbook(path);
      }
    }
    #endregion

    #region 公開メソッド
    /// <summary>
    /// 解放処理
    /// </summary>
    public void Dispose()
    {
      CloseExcel();
    }

    /// <summary>
    /// 引数で指定されたExcelファイルを開きます。
    /// </summary>
    /// <param name="path">Excelファイルのパス</param>
    /// <returns>true:オープン成功、false:オープン失敗</returns>
    public bool OpenExcel(string path)
    {
      CloseExcel();

      if (!string.IsNullOrEmpty(path) && File.Exists(path))
      {
        // ファイルパスが設定されているかつ、そのパスのファイルが存在する場合、ファイルを開く
        this._Workbook = new XLWorkbook(path);
        return true;
      }
      else
      {
        return false;
      }
    }

    /// <summary>
    /// 指定したインデックスのワークシートの指定セルを読み込みます。
    /// </summary>
    /// <param name="row">行番号</param>
    /// <param name="col">列番号</param>
    /// <param name="index">ワークシートのインデックス番号</param>
    /// <returns>true:オープン成功、false:オープン失敗</returns>
    public string ReadCell(int row, int col, int index = 1)
    {
      if (this._Workbook == null)
      {
        return string.Empty;
      }

      try
      {
        var worksheet = this._Workbook.Worksheet(index);
        var cell = worksheet.Cell(row, col);
        return cell.Value as String;
      }
      catch
      {
        // 指定されたワークシートが存在しなかった場合、空値を返却する
        return string.Empty;
      }
    }

    /// <summary>
    /// 指定したワークシートの指定セルを読み込みます。
    /// </summary>
    /// <param name="row">行番号</param>
    /// <param name="col">列番号</param>
    /// <param name="worksheet">ワークシートのインデックス番号</param>
    /// <returns>true:オープン成功、false:オープン失敗</returns>
    public string ReadCell(int row, int col, IXLWorksheet worksheet)
    {
      if (worksheet == null)
      {
        return string.Empty;
      }

      try
      {
        var cell = worksheet.Cell(row, col);
        return cell.Value as String;
      }
      catch
      {
        // 指定されたワークシートのセルが存在しなかった場合、空値を返却する
        return string.Empty;
      }
    }

    /// <summary>
    /// 現在オープンされているExcelファイルをクローズします。
    /// </summary>
    public void CloseExcel()
    {
      if (this._Workbook != null)
      {
        // 既にExcelが開かれている場合、破棄する
        this._Workbook.Dispose();
        this._Workbook = null;
      }
    }
    #endregion
  }
}

 クラスインスタンス生成時にExcelファイルのパスを指定し、Excelファイルからセルの読み込みを行う簡単なメソッドを実装したクラスです。
 COMオブジェクトの時代では速度面で遅く厳しいものがありましたが、ClosedXMLを使用した場合、速度もかなり速く利用を検討すべきだと思います。

イラストレーターで保存するとき「不明なエラーが発生しました」と出る!!保存できない人集合!!

イラストレーターで保存するとき「不明なエラーが発生しました」と出る!!保存できないじゃないか!!

という人向けの内容です!
私も出て困ったんですよねー、保存できないんですから。

 

そこで解決するために!最初はネットの情報にあったものを試してみました!

作業環境:Windows10、illustratorCC2017、メモリ8GBのデスクトップPC

 

イラレの環境ファイルを削除→PCを再起動
環境ファイルの場所は…
【users→ユーザー名→AppDate→Roaming→AdobeAdobe Illustrator 21 Settings→
ja_jp→x64→Adobe Illustrator Cloud Prefs】
Adobe Illustrator Cloud Prefsを削除する

別のサイトさんだと
【users→ユーザー名→AppDate→Roaming→AdobeAdobe Illustrator Settings→
ja_jp→x64→Adobe Illustrator Prefs】
Adobe Illustrator Prefsを削除する

でしたが、ファイルが見当たらなかったのでよく似たものを消してみました。
しかし直らないイラレが壊れることはありません)


・ファイルを作り直してコピーペーストする
直らなかった!

 

・バージョンを下げる
保存のバージョンを「illustrator CC→illustrator CS6」に変える
出なくなった!

 

・レイヤーのロックを外す
直る時と直らないときがある


(´・ω・`)え?分からないじゃん……

 

レイヤーの不具合じゃないかという話だけしか分かりませんでした。
が!作業の邪魔!なんとかしたい!って思ったので色々試しました。

とりあえず色々試したり調べたりして、回避できるかもしれない方法を見つけました。


多角形ツール+変形をして、その図形があるレイヤーをロック、または非表示にすると発生しました。
※あくまで自分の場合です

f:id:atamo_dev:20170714175640p:plain


多角形を作るだけならセーフでした。
でも、多角形作成後にその多角形の頂点や線をにゅーんと動かすとエラーが発生します

三角をよく多角形で作ってフキダシなんかを作る時に使っていました。
(次からは長方形ツールで作ろ……)

ただし、パスファインダーで合成してしまう、どこかの辺を消すなら問題ないです!
(その後変形しても問題なし)


あともう一つ試してみたのが、メモリが関係あるか
自分がいつも使っているPCは8GBです。

もう少しメモリの大きいPCでやったところ、エラーは発生しませんでした
もしかするとモリーの容量なのかも知れません。
実際のところ、原因って何なんだろう(´・ω・`)ウーン

 

多くのillustrator仲間の参考になると嬉しいです!

CocoaPodsでライブラリを公開する

プロジェクトを作成

まずはライブラリを作るためにプロジェクトを作成します。

XcodeでCreate new projectしてもいいのですが、CocoaPodsがテンプレートを公開しており、ターミナルから作成できるので今回はターミナルから作成していきます。

プロジェクト作成

以下のコマンドをターミナルで実行するとカレントディレクトリにプロジェクトが作成されます。

途中、幾つかの質問があるので、回答していきます。

pod lib create ライブラリ名

質問1 使用する言語はどちらですか?

What language do you want to use?? [ ObjC / Swift ]
> ObjC or Swift で回答

質問2 デモアプリを同梱しますか?

Would you like to include a demo application with your library? [ Yes / No ]
> Yes or No で回答

質問3 テストフレームワークを使いますか?

Which testing frameworks will you use? [ Quick / None ]
> Quick or None(使わない) で回答

質問4 Viewのテストを行いますか?

Would you like to do view based testing? [ Yes / No ]
> Yes or No で回答

成功するとXcodeが起動し、作成したプロジェクトが開きます。

ライブラリの作成

開いたプロジェクト内ソースツリーの[Pods]->[Development Pods]->[ライブラリ名]->[ライブラリ名]->[Classes]ReplaceMeというファイルがあるので、削除して自作ライブラリのファイルを配置します。

GitHubで公開

ライブラリのGitHubページを作成し、リポジトリのURLをコピーしておきます。

https://github.com/ユーザ名/ライブラリ名.git

プロジェクトファイル内のライブラリ名.podspecを編集します。

s.source: コピーしたリポジトリのURL

s.summary: 短い説明

s.description: 長い説明

#
# Be sure to run `pod lib lint ライブラリ名.podspec' to ensure this is a
# valid spec before submitting.
#
# Any lines starting with a # are optional, but their use is encouraged
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
#

Pod::Spec.new do |s|
  s.name             = 'ライブラリ名'
  s.version          = '0.1.0'
  s.summary          = 'A short description of ライブラリ名.'

# This description is used to generate tags and improve search results.
#   * Think: What does it do? Why did you write it? What is the focus?
#   * Try to keep it short, snappy and to the point.
#   * Write the description between the DESC delimiters below.
#   * Finally, don't worry about the indent, CocoaPods strips it!

  s.description      = <<-DESC
TODO: Add long description of the pod here.
                       DESC

  s.homepage         = 'https://github.com/ユーザ名/ライブラリ名'
  # s.screenshots     = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2'
  s.license          = { :type => 'MIT', :file => 'LICENSE' }
  s.author           = { 'ユーザ名' => 'メールアドレス' }
  s.source           = { :git => 'https://github.com/ユーザ名/ライブラリ名.git', :tag => s.version.to_s }
  # s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'

  s.ios.deployment_target = '8.0'

  s.source_files = 'ライブラリ名/Classes/**/*'
  
  # s.resource_bundles = {
  #   'ライブラリ名' => ['ライブラリ名/Assets/*.png']
  # }

  # s.public_header_files = 'Pod/Classes/**/*.h'
  # s.frameworks = 'UIKit', 'MapKit'
  # s.dependency 'AFNetworking', '~> 2.3'
end

編集後、GitHubリポジトリにPushします。

Xcode上からSource Controlブランチ名Configure ライブラリ名を開き、RemoteからGitHubリポジトリを追加します。

Source ControlCommitを選択し、左下のPush to remoteへチェックを入れたらCommit Filesを押下します。

バージョンの指定

CocoaPods上でのバージョンはGitのタグに対応するので、ターミナルから公開時のバージョンをタグで付けます

git tag 1.0.0

リモートに反映します

git push 1.0.0

確認

podspecに誤りがないか確認します。

ターミナルでプロジェクトのディレクトリへ移動し、以下のコマンドを実行します。

pod lib lint

エラー場表示される場合は修正します。

(僕は説明が短すぎると言うエラーが出ました

CocoaPods trunkへ登録する

ターミナルでコマンドを実行します

pod trunk register 公開するメール '公開する名前' --description='説明'

入力したメールアドレスへ確認メールが来るので記載されているリンクを押下します。

ターミナル上で以下のコマンドを実行して名前が表示されていれば登録が完了しています。

pod trunk me

CocoaPods trunkへ登録します。

以下のコマンドを実行

pod trunk push ライブラリ名.podspec

pod try ライブラリ名 を実行してサンプルプロジェクトが開けば登録できています。