ゆるい感じのプログラムを書きたい。

プログラムの敷居を下げて、多くの人が開発出来るように色々書いていきます!

【iPhoneアプリ】プロパティとは

以前、「【iPhoneアプリ】基本を忘れないように「オブジェクト指向」について」の回で

記載した際に、オブジェクト指向では、 メソッドで「引数に値を代入してクラスの値を更新したり」「クラスの値を取得したり」を 作成し行うと書きました。

そのような機能を「アクセッサメソッドといいます。


アクセサメソッドsetter(値更新)」「sgetter(値取得)」を自分で記述するのは 非常にめんどくさくて書きたくないです。

そのため、Object-cでは「@property」を利用することにより 「getter」「setter」の記述を省く事が出来 また、以下の要素を持たせる事が可能となります。

アクセス制限

プロパティ属性 意味
readwrite getter(読込み)/setter(書込み)両方利用可能(デフォルト指定)
readonly setter(読込み)のみ可能

オブジェクトを代入する際の操作

手動メモリ管理(MRC: Manual Reference Counting)の場合
プロパティ属性 意味
retain オブジェクトをretain(カウンターを1加算)してから代入
assign オブジェクトをそのまま代入(デフォルト)
copy オブジェクトをcopyしてから代入
自動メモリ管理(ARC: Automatic Reference Counting)の場合
プロパティ属性 意味
strong オブジェクトをretain(カウンターを1加算)してから代入
weak オブジェクトをそのまま代入(デフォルト)
copy オブジェクトをcopyしてから代入
その他
プロパティ属性 意味
unsafe_unretained オーナーシップ権を持たないプロパティ

アクセッサメソッド

プロパティ属性 意味
getter=GETメソッド GETメソッド名の指定
setter=SETメソッド SETメソッド名の指定

マルチスレッドからのアクセス時の処理

プロパティ属性 意味
atomic アクセス時に同期処理で処理を行う
nonatomic アクセス時に非同期処理で処理を行う

では、実際にソースを書いて、図でも表現してみます。

Retain(Strong)の説明

  • 下記のように「retain」を利用した、propertyを作成します。
//property宣言 データ型_setter,getter名前指定なし
@property (nonatomic,retain) NSObject *object_charcter2;

この場合、以下の図のような使われ方となります。

  • Retainを使うときはこんな感じです。

f:id:kassans:20140913111753p:plain

  • Retainを使い終わった後はこんな感じです。

f:id:kassans:20140913111819p:plain

上記のRetainには下記のようなデメリットもあります。

  • デメリットはこんな感じです。

f:id:kassans:20140913111914p:plain

f:id:kassans:20140913111930p:plain


Assign(Weak)の説明

  • 下記のように「assign」を利用した、propertyを作成します。
//property宣言 データ型_setter,getter名前指定なし
@property (nonatomic,assign) char   charcter1;

この場合、以下の図のような使われ方となります。

  • Assignを使うときはこんな感じです。

f:id:kassans:20140913112012p:plain

  • Assignを使い終わった後はこんな感じです。

f:id:kassans:20140913112028p:plain


Copyの説明

  • 下記のように「copy」を利用した、propertyを作成します。
//property宣言 データ型_setter,getter名前指定なし
@property (nonatomic,copy) NSObject *object_charcter2;

この場合、以下の図のような使われ方となります。

  • Copyを使うときはこんな感じです。

f:id:kassans:20140913112047p:plain

  • Copyを使い終わった後はこんな感じです。

f:id:kassans:20140913112102p:plain

上記のCopyには下記のようなメリットもあります。

  • メリットはこんな感じです。

f:id:kassans:20140913112118p:plain

f:id:kassans:20140913112135p:plain

MRCとARCの違い

Javaのガーベージコレクションに似ているため、 ガーベージコレクションをイメージして図を作成しております。

MRCの場合このようにメモリを解放します。

f:id:kassans:20140913112329p:plain

f:id:kassans:20140913112412p:plain

ARCの場合このようにメモリーを解放します。

f:id:kassans:20140913112205p:plain

次回は、実装編を記載していきます。

【iPhoneアプリ】これは便利かも!?「block構文」について

今回は、「block構文」についてです。

block構文とは、iOS4.0から利用可能となった機能です
その場で関数を式として作成でき、JavaScriptで言うと「クロージャ」になります。

ちなみに、「クロージャ」とは


こんな感じにプログラムを書きます。

function object() {
  var value = 0;

  function add(num) {
    value += num*2;
  }

  //内部function「add」を呼び出し	
  add(100);
  console.log("結果:"value); 
}

//function「object」を呼び出し
object();


コンソールログはこんな感じです。

結果:200


block構文の記述方法

以下のようにblock構文を記述します。


■基本的な書き方

^(仮引数){
 //実行する処理
};


■block構文を代入する書き方

戻り値 (^変数名)(引数) = ^(仮引数){
  //実行する処理
};


typedefを利用したblockの型を作成

■「typedef」を利用して作成
【例:引数の合計値を返すblock構文】


プログラムはこんな感じに書きます。

#import "ViewController.h"

@interface ViewController ()
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    //ブロックの型の作成する
    typedef int (^math)(int,int);

    //引数の合計値を求めて戻り値で返す
    math sum  = ^(int num1,int num2) {
      return num1 + num2;
    };

    //求めた値を表示
    NSLog(@"合計値:%d",sum(100,100));
}

@end


結果はこんな感じです。

labo[24373:60b] 合計値:200


ソースの解析はこんな感じです。

f:id:kassans:20140402151358p:plain

レキシカルスコープを用いたblock構文を作成

通常、block構文外で宣言された変数block構文内で変更する事は出来ません。
しかし、変数宣言時に「__block」修飾子を付ける事でblock構文内でも変更が可能
なります。


プログラムはこんな感じに書きます。

#import "ViewController.h"

@interface ViewController ()
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    //レキシカルスコープ用の変数を宣言
    __block int num = 100;

    //レキシカルスコープ用の変数を用いた計算処理
    int (^math)(void) = ^(void){
      return num*2;
    };

    //求めた値を表示
    NSLog(@"合計値:%d",math());
}
@end


結果はこんな感じです。

labo[24373:60b] 合計値:200


ソースの解析はこんな感じです。

f:id:kassans:20140402151806p:plain

引数にブロック構文を用いたメソッドを作成

引数にブロック構文を記載し、以下の処理を行う事が出来ます。


プログラムはこんな感じに書きます。

#import "ViewController.h"

@interface ViewController ()
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    int num = 100;
    
    //block構文を用いたメソッドを呼び出し
    [self example:num block:^(int n){
       //block構文内の処理
       return n*2;
    }];

}

//引数にblock構文を含めたメソッド
- (void)example:(int)num block:(int(^)(int))method
{
    NSLog(@"合計値:%d",method(num));
}
@end


結果はこんな感じです。

 labo[24405:60b] 合計値:200


ソースの解析はこんな感じです。

f:id:kassans:20140402152047p:plain

【iPhoneアプリ】他にもまだまだあった「マルチスレッド」について dispatch_group_xxxxxx編

今回は、「マルチスレッド dispatch_group_xxxxx編」についてです。

2部構成の2部目「dispatch_group_xxxxx編」について記載します。
今回は、1ページで収まっております。

dispatch_groupについて

・「dispatch_group」は、いくつかの処理を分散処理させ、結果をまとめて処理を
 行いたい時に利用します。

また、「dispatch_group」には、下記のような種類のメソッドを利用できます。


■dispatch_group_create
・ブロックオブジェクトを関連させる事が可能な新しいグループを作成します。

引数 説明
void 引数指定無し


■dispatch_group_async
・引数で記述したブロック構文の処理を行う、指定したキューオブジェクトに
 グループの関連付けを行う

引数 説明
dispatch_group_t ディスパチグループオブジェクト
dispatch_queue_t ディスパチキューオブジェクト
dispatch_block_t タスク処理が書かれたblock構文


■dispatch_group_async_f
・引数で指定した関数の処理を行う、指定されたキューオブジェクトにグループ
 の関連付けを行う。

引数 説明
dispatch_group_t ディスパチグループオブジェクト
dispatch_queue_t ディスパチキューオブジェクト
void * 関数の引数:汎用ポインタ
dispactch_function 関数名


■dispatch_group_enter
・グループの関連付けを開始する。
(本当はもっと内容は複雑ですが、簡単に理解する為このように記載します。)

引数 説明
dispatch_group_t ディスパチグループオブジェクト


■dispatch_group_leave
・グループの関連付けを終了する。
(本当はもっと内容は複雑ですが、簡単に理解する為このように記載します。)

引数 説明
dispatch_group_t ディスパチグループオブジェクト


■dispatch_group_notify
・グループ内のブロック処理が完了後、記載されたblock構文の処理を行う
 「dispatch_group_wait」は待たなく、次の処理へ進む。

引数 説明
dispatch_group_t ディスパチグループオブジェクト
dispatch_queue_t ディスパチキューオブジェクト
dispatch_block_t タスク処理が書かれたblock構文


■dispatch_group_notify_f
・グループ内のブロック処理が完了後、記載された関数の処理を行う
 「dispatch_group_wait」は待たなく、次の処理へ進む。

引数 説明
dispatch_group_t ディスパチグループオブジェクト
dispatch_queue_t ディスパチキューオブジェクト
void * 関数の引数:汎用ポインタ
dispactch_function 関数名


■dispatch_group_wait
・グループ内の全てのブロック処理を待つ。

引数 説明
dispatch_group_t ディスパチグループオブジェクト
timeout 待ち時間をdispatch_time_t 型(unit64_t型)を使ってナノ秒単位で指定


「dispatch_group_async」を用いたグループ処理


・プログラムはこんな感じに書きます。

- (IBAction)thread_Button:(UIButton*)sender
{

   //グローバルキューの作成
   dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
   //DispatchGroup の生成
   dispatch_group_t group = dispatch_group_create();
   
   /*
    * グループ処理1 
    */
   for (NSInteger i = 0 ; i < 5; ++i) {
     dispatch_group_async(group,queue, ^{
       NSLog(@"グループ_処理1_実行回数:%d %p", i,[NSThread currentThread]);
     });
   }

   /*
    * グループ処理2 
    */
   for (NSInteger i = 0 ; i < 5; ++i) {
     dispatch_group_async(group,con_queue, ^{
       NSLog(@"グループ_処理2_実行回数:%d %p",i,[NSThread currentThread]);
     });
   }

   //グループのblock処理終了まで待機
   dispatch_group_wait(group,DISPATCH_TIME_FOREVER);
   NSLog(@"同期処理:%p",[NSThread currentThread]);
}


・結果はこんな感じです。

labo[23106:3707] グループ_処理1_実行回数:1 0x17595ea0
labo[23106:1803] グループ_処理1_実行回数:0 0x17668590
labo[23106:1803] グループ_処理1_実行回数:2 0x17668590
labo[23106:1803] グループ_処理1_実行回数:3 0x17668590
labo[23106:1803] グループ_処理2_実行回数:0 0x17668590
labo[23106:3707] グループ_処理1_実行回数:4 0x17595ea0
labo[23106:1803] グループ_処理2_実行回数:1 0x17668590
labo[23106:3707] グループ_処理2_実行回数:2 0x17595ea0
labo[23106:1803] グループ_処理2_実行回数:3 0x17668590
labo[23106:3707] グループ_処理2_実行回数:4 0x17595ea0
labo[23106:60b] 同期処理:0x17559a80

この処理では、2つの「dispatch_group_async」が実行された後、「同期処理」が実行されている事が分かります。


「dispatch_group_enter」「dispatch_group_leave」を用いたグループ処理


・プログラムはこんな感じに書きます。

- (IBAction)thread_Button:(UIButton*)sender
{

   //グローバルキューの作成
   dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
   //DispatchGroup の生成
   dispatch_group_t group = dispatch_group_create();

   /*
    * グループ処理1 
    */
   for (NSInteger i = 0 ; i < 5; ++i) {
      //グループの関連付けを開始する。
      dispatch_group_enter(group);
      //「dispatch_group_async」ではない非同期処理を実施	
      dispatch_async(queue, ^{
         NSLog(@"グループ_処理1_実行回数:%d %p", i,[NSThread currentThread]);
         //グループの関連付けを終了する。
         dispatch_group_leave(group);
         //ここはグループ化されてないので待ってない。
         NSLog(@"グループ外_処理1_実行回数:%d %p", i,[NSThread currentThread]);
      });
   }

   //グループのblock処理終了まで待機
   dispatch_group_wait(group,DISPATCH_TIME_FOREVER);
   NSLog(@"同期処理:%p",[NSThread currentThread]);
}


・結果はこんな感じです。

labo[23715:1803] グループ_処理1_実行回数:0 0x14625cf0
labo[23715:3707] グループ_処理1_実行回数:1 0x145526c0
labo[23715:1803] グループ外_処理1_実行回数:0 0x14625cf0
labo[23715:1803] グループ_処理1_実行回数:2 0x14625cf0
labo[23715:3707] グループ外_処理1_実行回数:1 0x145526c0
labo[23715:1803] グループ外_処理1_実行回数:2 0x14625cf0
labo[23715:3707] グループ_処理1_実行回数:3 0x145526c0
labo[23715:1803] グループ_処理1_実行回数:4 0x14625cf0
labo[23715:3707] グループ外_処理1_実行回数:3 0x145526c0
labo[23715:60b]  同期処理:0x14518150
labo[23715:1803] グループ外_処理1_実行回数:4 0x14625cf0

この処理では、グループの関連づけされていない「グループ外_処理1」の処理を待たずに「同期処理」が実行されている事が分かります。


・イメージはこんな感じです。

f:id:kassans:20140331192650p:plain


「dispatch_group_notify」を用いたグループ処理


・プログラムはこんな感じに書きます。

- (IBAction)thread_Button:(UIButton*)sender
{

   //グローバルキューの作成
   dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
   //DispatchGroup の生成
   dispatch_group_t group = dispatch_group_create();

   /*
    * グループ処理1 
    */
   for (NSInteger i = 0 ; i < 5; ++i) {
      //グループの関連付けを開始する。
      dispatch_group_enter(group);
      //「dispatch_group_async」ではない非同期処理を実施	
      dispatch_async(queue, ^{
         NSLog(@"グループ_処理1_実行回数:%d %p", i,[NSThread currentThread]);
         //グループの関連付けを終了する。
         dispatch_group_leave(group);
         //ここはグループ化されてないので待ってない。
         NSLog(@"グループ外_処理1_実行回数:%d %p", i,[NSThread currentThread]);
      });
   }
   
   /*
    * グループ処理2
    */
   dispatch_group_async(group,con_queue, ^{
       NSLog(@"グループ_処理2 %p",[NSThread currentThread]);
   });
   
   //グループ処理完了後の処理
   dispatch_group_notify(group, queue, ^{
       NSLog(@"グループ処理終了後の処理 %p",[NSThread currentThread]);
   });
    
   //グループのblock処理終了まで待機
   dispatch_group_wait(group,DISPATCH_TIME_FOREVER);
   NSLog(@"同期処理:%p",[NSThread currentThread]);

}


・結果はこんな感じです。

labo[23747:3707] グループ_処理1_実行回数:1 0x15595ba0
labo[23747:1803] グループ_処理1_実行回数:0 0x156a8190
labo[23747:1803] グループ_処理1_実行回数:3 0x156a8190
labo[23747:3707] グループ_処理1_実行回数:2 0x15595ba0
labo[23747:1803] グループ_処理1_実行回数:4 0x156a8190
labo[23747:3707] グループ_処理2 0x15595ba0
labo[23747:60b]  同期処理:0x1567ef60
labo[23747:3707] グループ処理終了後の処理 0x15595ba0

この処理では、「同期処理」が実行され、同時に「dispatch_group_notify」が実行されている事が分かります。


・イメージはこんな感じです。

f:id:kassans:20140401114738p:plain

【iPhoneアプリ】他にもまだまだあった「マルチスレッド」について dispatch_xxxxx編続き

今回もまた、「マルチスレッド」についてです。

前回の「dispatch_xxxxx」について
ですが、記載しきれなかった為、今回は続きを記載します。

続きで記載出来なかったdispatch_xxxxについて

■dispatch_barrier_async

・非同期処理の完了を待つ、もしくは非同期処理の間にblock構文の内容を
 処理したい場合


※処理は非同期で行いますが、前後の処理の整合性を取るため見た目は同期です。

引数 説明
dispatch_queue_t ディスパチキューオブジェクト
dispatch_block_t タスク処理が書かれたblock構文

<注意>
グローバルキュー、プライベートのシリアルキューでは機能しません。
プライベートのコンカレントキューのみ機能します。


こんな感じのプログラムを書きます。

- (IBAction)thread_Button:(UIButton*)sender
{
  dispatch_queue_t queue = dispatch_queue_create("jp.test.sample", DISPATCH_QUEUE_CONCURRENT);

  //非同期処理1
  dispatch_apply(5,queue,^(size_t i){
   NSLog(@"非同期1_処理回数:%d",(int)i);
  });

  //非同期処理2
  dispatch_async(queue,^{
    for(int i=0;i<5;i++){
      NSLog(@"非同期2_処理回数:%d",(int)i);
    }
  });

  //バリアされた非同期処理
  dispatch_barrier_async(queue,^{
    NSLog(@"dispatch_barrier_async");
  });

  //非同期処理3    
  dispatch_apply(5,queue,^(size_t i){
    NSLog(@"非同期3_処理回数:%d",(int)i);
  });
}


結果はこんな感じです。

labo[21289:60b]  非同期1_処理回数:0
labo[21289:60b]  非同期1_処理回数:2
labo[21289:60b]  非同期1_処理回数:3
labo[21289:60b]  非同期1_処理回数:4
labo[21289:1803] 非同期1_処理回数:1
labo[21289:3707] 非同期2_処理回数:0
labo[21289:3707] 非同期2_処理回数:1
labo[21289:3707] 非同期2_処理回数:2
labo[21289:3707] 非同期2_処理回数:3
labo[21289:3707] 非同期2_処理回数:4
labo[21289:3707] dispatch_barrier_async
labo[21289:60b]  非同期3_処理回数:0
labo[21289:60b]  非同期3_処理回数:1
labo[21289:60b]  非同期3_処理回数:2
labo[21289:60b]  非同期3_処理回数:4
labo[21289:1803] 非同期3_処理回数:3

dispatch_barrier_asyncを使うと、先行処理「非同期処理1」「非同期処理2」
終わるまで処理実行を待つ、そして、dispatch_barrier_async内の処理が完了するまで
後続の「非同期処理3」の処理は実行されない。


■dispatch_barrier_async_f

・非同期処理の完了を待つ、もしくは非同期処理の間にblock構文ではなく、関数を
 利用したい場合。


※処理は非同期で行いますが、前後の処理の整合性を取るため見た目は同期です。

引数 説明
dispatch_queue_t ディスパチキューオブジェクト
void * 関数の引数:汎用ポインタ
dispactch_function 関数名

<注意>
グローバルキュー、プライベートのシリアルキューでは機能しません。
プライベートのコンカレントキューのみ機能します。


こんな感じのプログラムを書きます。

- (IBAction)thread_Button:(UIButton*)sender
{
  dispatch_queue_t queue = dispatch_queue_create("jp.test.sample", DISPATCH_QUEUE_CONCURRENT);

  //非同期処理1
  dispatch_apply(5,queue,^(size_t i){
   NSLog(@"非同期1_処理回数:%d",(int)i);
  });

  //非同期処理2
  dispatch_async(queue,^{
    for(int i=0;i<5;i++){
      NSLog(@"非同期2_処理回数:%d",(int)i);
    }
  });

  //バリアされた非同期処理
  dispatch_barrier_async_f(queue,(void *)int_obj,barrier_method);

  //非同期処理3    
  dispatch_apply(5,queue,^(size_t i){
    NSLog(@"非同期3_処理回数:%d",(int)i);
  });
}

//呼び出すメソッド
void barrier_method(void *context)
{
  NSLog(@"引数のvoid_ポインタ値:%d",(int)context);
}


結果はこんな感じです。

labo[21326:60b]  非同期1_処理回数:0
labo[21326:1803] 非同期1_処理回数:1
labo[21326:60b]  非同期1_処理回数:2
labo[21326:1803] 非同期1_処理回数:3
labo[21326:60b]  非同期1_処理回数:4
labo[21326:1803] 非同期2_処理回数:0
labo[21326:1803] 非同期2_処理回数:1
labo[21326:1803] 非同期2_処理回数:2
labo[21326:1803] 非同期2_処理回数:3
labo[21326:1803] 非同期2_処理回数:4
labo[21326:1803] 引数のvoid_ポインタ値:20
labo[21326:60b]  非同期3_処理回数:0
labo[21326:1803] 非同期3_処理回数:1
labo[21326:1803] 非同期3_処理回数:3
labo[21326:1803] 非同期3_処理回数:4
labo[21326:60b]  非同期3_処理回数:2

dispatch_barrier_async_fを使うと、先行処理「非同期処理1」「非同期処理2」
終わるまで処理実行を待つ、そして、dispatch_barrier_async内の処理が完了するまで
後続の「非同期処理3」の処理は実行されない。


■dispatch_barrier_sync

・非同期処理の完了を待つ、もしくは非同期処理の間にblock構文の処理をする場合。


※処理は同期で行います。

引数 説明
dispatch_queue_t ディスパチキューオブジェクト
dispatch_block_t タスク処理が書かれたblock構文

<注意>
グローバルキュー、プライベートのシリアルキューでは機能しません。
プライベートのコンカレントキューのみ機能します。


こんな感じのプログラムを書きます。

- (IBAction)thread_Button:(UIButton*)sender
{
  dispatch_queue_t queue = dispatch_queue_create("jp.test.sample", DISPATCH_QUEUE_CONCURRENT);

  //非同期処理1
  dispatch_apply(5,queue,^(size_t i){
   NSLog(@"非同期1_処理回数:%d",(int)i);
  });

  //非同期処理2
  dispatch_async(queue,^{
    for(int i=0;i<5;i++){
      NSLog(@"非同期2_処理回数:%d",(int)i);
    }
  });

  //バリアされた非同期処理
  dispatch_barrier_sync(queue,^{
    NSLog(@"dispatch_barrier_async");
  });

  //非同期処理3    
  dispatch_apply(5,queue,^(size_t i){
    NSLog(@"非同期3_処理回数:%d",(int)i);
  });
}


結果はこんな感じです。

labo[21348:1803] 非同期1_処理回数:1
labo[21348:60b]  非同期1_処理回数:0
labo[21348:60b]  非同期1_処理回数:3
labo[21348:1803] 非同期1_処理回数:2
labo[21348:60b]  非同期1_処理回数:4
labo[21348:1803] 非同期2_処理回数:0
labo[21348:1803] 非同期2_処理回数:1
labo[21348:1803] 非同期2_処理回数:2
labo[21348:1803] 非同期2_処理回数:3
labo[21348:1803] 非同期2_処理回数:4
labo[21348:60b]  dispatch_barrier_async
labo[21348:60b]  非同期3_処理回数:0
labo[21348:60b]  非同期3_処理回数:2
labo[21348:60b]  非同期3_処理回数:3
labo[21348:1803] 非同期3_処理回数:1
labo[21348:60b]  非同期3_処理回数:4

dispatch_barrier_sync_fを使うと、先行処理「非同期処理1」「非同期処理2」が
終わるまで処理実行を待つ、そして、dispatch_barrier_async内の処理が完了するまで
後続の「非同期処理3」の処理は実行されない。


■dispatch_barrier_sync_f

・非同期処理の完了を待つ、もしくは非同期処理の間にblock構文ではなく、関数を
 利用したい場合。


※処理は同期で行います。

引数 説明
dispatch_queue_t ディスパチキューオブジェクト
void * 関数の引数:汎用ポインタ
dispactch_function 関数名

<注意>
グローバルキュー、プライベートのシリアルキューでは機能しません。
プライベートのコンカレントキューのみ機能します。


こんな感じのプログラムを書きます。

- (IBAction)thread_Button:(UIButton*)sender
{
  dispatch_queue_t queue = dispatch_queue_create("jp.test.sample", DISPATCH_QUEUE_CONCURRENT);

  //非同期処理1
  dispatch_apply(5,queue,^(size_t i){
   NSLog(@"非同期1_処理回数:%d",(int)i);
  });

  //非同期処理2
  dispatch_async(queue,^{
    for(int i=0;i<5;i++){
      NSLog(@"非同期2_処理回数:%d",(int)i);
    }
  });

  //バリアされた非同期処理
  dispatch_barrier_async_f(queue,(void *)int_obj,barrier_method);

  //非同期処理3    
  dispatch_apply(5,queue,^(size_t i){
    NSLog(@"非同期3_処理回数:%d",(int)i);
  });
}

//呼び出すメソッド
void barrier_method(void *context)
{
  NSLog(@"引数のvoid_ポインタ値:%d",(int)context);
}


結果はこんな感じです。

labo[21358:60b]  非同期1_処理回数:0
labo[21358:1803] 非同期1_処理回数:1
labo[21358:1803] 非同期1_処理回数:2
labo[21358:60b]  非同期1_処理回数:4
labo[21358:1803] 非同期1_処理回数:3
labo[21358:1803] 非同期2_処理回数:0
labo[21358:1803] 非同期2_処理回数:1
labo[21358:1803] 非同期2_処理回数:2
labo[21358:1803] 非同期2_処理回数:3
labo[21358:1803] 非同期2_処理回数:4
labo[21358:60b]  引数のvoid_ポインタ値:20
labo[21358:60b]  非同期3_処理回数:0
labo[21358:1803] 非同期3_処理回数:1
labo[21358:1803] 非同期3_処理回数:3
labo[21358:60b]  非同期3_処理回数:2
labo[21358:1803] 非同期3_処理回数:4

dispatch_barrier_sync_fを使うと、先行処理「非同期処理1」「非同期処理2」
終わるまで処理実行を待つ、そして、dispatch_barrier_async内の処理が完了するまで
後続の「非同期処理3」の処理は実行されない。


■dispatch_suspend

・キューの処理を一時的に中断させる。

<注意>
プライベートのシリアルキュー、コンカレントキューのみ機能します。


こんな感じのプログラムを書きます。

- (IBAction)thread_Button:(UIButton*)sender
{

  dispatch_queue_t con_queue = dispatch_queue_create("jp.test.sample", DISPATCH_QUEUE_CONCURRENT);
 
  dispatch_apply(5,con_queue,^(size_t i){
   NSLog(@"非同期1_処理回数:%d",(int)i);
  });

  //con_queueを一時的に停止
  dispatch_suspend(con_queue);
   
  dispatch_apply(5,con_queue,^(size_t i){
    NSLog(@"非同期2_処理回数:%d",(int)i);
  });
}


結果はこんな感じです。

labo[21465:60b]  非同期1_処理回数:0
labo[21465:1803] 非同期1_処理回数:1
labo[21465:1803] 非同期1_処理回数:3
labo[21465:60b]  非同期1_処理回数:2
labo[21465:1803] 非同期1_処理回数:4

dispatch_suspendがの処理以降は、「con_queue」キューが一時停止されているため
処理がされていない。


また、シリアルキューコンカレント2つのキューを組み合わせて
処理を行ってみる。


こんな感じのプログラムを記載します。

- (IBAction)thread_Button:(UIButton*)sender
{

  dispatch_queue_t con_queue = dispatch_queue_create("jp.test.sample", DISPATCH_QUEUE_CONCURRENT);
  dispatch_queue_t sri_queue = dispatch_queue_create("jp.test.sample", DISPATCH_QUEUE_SERIAL);
    
  dispatch_apply(5,con_queue,^(size_t i){
    NSLog(@"非同期1_処理回数:%d",(int)i);
  });

  //con_queueを一時的に停止
  dispatch_suspend(con_queue);
   
  dispatch_apply(5,sri_queue,^(size_t i){
    NSLog(@"非同期4_処理回数:%d",(int)i);
  });
    
	//con_queueを再開
  dispatch_resume(con_queue);


結果はこんな感じです。

labo[21499:60b]  非同期1_処理回数:0
labo[21499:60b]  非同期1_処理回数:2
labo[21499:60b]  非同期1_処理回数:3
labo[21499:60b]  非同期1_処理回数:4
labo[21499:1803] 非同期1_処理回数:1
labo[21499:60b]  非同期4_処理回数:0
labo[21499:60b]  非同期4_処理回数:1
labo[21499:60b]  非同期4_処理回数:2
labo[21499:60b]  非同期4_処理回数:3
labo[21499:60b]  非同期4_処理回数:4

dispatch_suspendがの処理以降は、「con_queue」キューが一時停止されているが
次の処理が「sri_queue」で別キューの為、処理が継続される。


■dispatch_suspend

・一時的に中断させていた、キューを再開させる。

<注意>
プライベートのシリアルキュー、コンカレントキューのみ機能します。


こんな感じのプログラムを書きます。

- (IBAction)thread_Button:(UIButton*)sender
{
   dispatch_queue_t con_queue = dispatch_queue_create("jp.test.sample", DISPATCH_QUEUE_CONCURRENT);

   dispatch_apply(5,con_queue,^(size_t i){
     NSLog(@"非同期1_処理回数:%d",(int)i);
   });

   //con_queueを一時的に停止
   dispatch_suspend(con_queue);

   //mainキュー処理
   for(int i=0;i<5;i++){
     NSLog(@"main_処理回数:%d",(int)i);
   }

   //con_queueを再開
   dispatch_resume(con_queue);

   dispatch_apply(5,con_queue,^(size_t i){
     NSLog(@"非同期2_処理回数:%d",(int)i);
   });


結果はこんな感じです。

labo[21508:60b]  非同期1_処理回数:0
labo[21508:1803] 非同期1_処理回数:1
labo[21508:60b]  非同期1_処理回数:2
labo[21508:1803] 非同期1_処理回数:3
labo[21508:60b]  非同期1_処理回数:4
labo[21508:60b]  main_処理回数:0
labo[21508:60b]  main_処理回数:1
labo[21508:60b]  main_処理回数:2
labo[21508:60b]  main_処理回数:3
labo[21508:60b]  main_処理回数:4
labo[21508:60b]  非同期2_処理回数:0
labo[21508:60b]  非同期2_処理回数:2
labo[21508:60b]  非同期2_処理回数:3
labo[21508:60b]  非同期2_処理回数:4
labo[21508:1803] 非同期2_処理回数:1

dispatch_suspendがの処理以降は、「con_queue」キューが停止され
「main」キューの処理後dispatch_resume「con_queue」キューの処理が再開される。


■dispatch_semaphore

・非同期処理から同期処理を行いたい場合に利用する。


▼dispatch_semaphore_create()

・初期値を使用して新しい「CountingSemaphore」を作成します。

型名 説明
long値 カウントの数


▼dispatch_semaphore_signal

・「CountingSemaphore」をインクリメント(増やす)します。

型名 説明
dispatch_semaphore_t カウンティングセマフォ


▼dispatch_semaphore_wait

・「CountingSemaphore」をデクリメント(減らす)します。

型名 説明
dispatch_semaphore_t カウンティングセマフォ
dispatch_time_t タイムアウト時間設定


<注意>
グローバルキュー、プライベートのシリアルキュー、コンカレントキューのみ
機能します。


こんな感じのプログラムを書きます。

- (IBAction)thread_Button:(UIButton*)sender
{
   dispatch_queue_t con_queue = dispatch_queue_create("jp.test.sample", DISPATCH_QUEUE_CONCURRENT);

   dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
   
	 dispatch_async(sri_queue, ^{
     //async内の処理開始
     for (int i = 1; i <= 5; i++) {
       NSLog(@"非同期_async内処理_%d:%p",i,[NSThread currentThread]);
     }
     //非同期処理完了
		 dispatch_semaphore_signal(semaphore);
   }

   NSLog(@"非同期_async外処理:%p",[NSThread currentThread]);
   //非同期処理終了待ち
   dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
   
   NSLog(@"同期_メイン処理:%p",[NSThread currentThread]);

}


結果はこんな感じです。

20:54:39.125 labo[22427:60b]  非同期_async外処理:0x14556c60
20:54:39.126 labo[22427:1803] 非同期_async内処理_1:0x1465b080
20:54:39.126 labo[22427:1803] 非同期_async内処理_2:0x1465b080
20:54:39.128 labo[22427:1803] 非同期_async内処理_3:0x1465b080
20:54:39.129 labo[22427:1803] 非同期_async内処理_4:0x1465b080
20:54:39.130 labo[22427:1803] 非同期_async内処理_5:0x1465b080
20:54:39.131 labo[22427:60b]  同期_メイン処理:0x14556c60

ログを見ると「非同期_async内処理」「非同期_async外処理」両方の処理が終わるまで
同期_メイン処理」が待っているため、非同期処理から同期処理が可能となります。


■どのように非同期から同期になっているのか


プログラム解説

f:id:kassans:20140328140059p:plain


動作のイメージ

f:id:kassans:20140328140118p:plain


dispatch_semaphoreを複数用いた場合のイメージ

f:id:kassans:20140328140207p:plain

ちなみに、参考に「dispatch_semaphore」を利用しない場合は、以下のような
感じになります。


プログラムはこんな感じです。

- (IBAction)thread_Button:(UIButton*)sender
{
   dispatch_queue_t con_queue = dispatch_queue_create("jp.test.sample", DISPATCH_QUEUE_CONCURRENT);

   dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
     dispatch_async(sri_queue, ^{
       for (int i = 1; i <= 5; i++) {
         NSLog(@"非同期_async内処理_%d:%p",i,[NSThread currentThread]);
       }
     });
    
   NSLog(@"非同期_async外処理:%p",[NSThread currentThread]);
   NSLog(@"同期_メイン処理:%p",[NSThread currentThread]);


結果はこんな感じです。

labo[22733:60b]  非同期_async外処理:0x14e525b0
labo[22733:1803] 非同期_async内処理_1:0x14d7dec0
labo[22733:60b]  同期_メイン処理:0x14e525b0
labo[22733:1803] 非同期_async内処理_2:0x14d7dec0
labo[22733:1803] 非同期_async内処理_3:0x14d7dec0
labo[22733:1803] 非同期_async内処理_4:0x14d7dec0
labo[22733:1803] 非同期_async内処理_5:0x14d7dec0

上記の結果、非同期処理を待たずに同期処理がされているのが
わかると思います。


■スレッド処理作成時に使えるログ出力方法

NSObjectの「NSThread」の以下のメソッドを使います。


▼isMainThread
メインスレッドを利用しているのかを確認します。

・記載例

NSLog(@"MainThread使用中:%d", [NSThread isMainThread]);

・ログ

MainThread使用中:1
//0:未使用
//1:利用中


▼isMultiThreaded
マルチスレッドを利用しているのかを確認します。

・記載例

NSLog(@"MainThread使用中:%d", [NSThread isMainThread]);

・ログ

MultiThread使用中:1
//0:未使用
//1:利用中


▼currentThread
現在使用中のスレッドオブジェクトのアドレス値が返ってきます。

・記載例

NSLog(@"スレッドオブジェクト値:%p",[NSThread currentThread]);

・ログ

スレッドオブジェクト値:0x15574c70

【iPhoneアプリ】他にもまだまだあった「マルチスレッド」について dispatch_xxxxx編

今回もまた、「マルチスレッド」についてです。

以前は「概要編」「実装編」として、基本的な使用法を記載致しましたが
今回は、その他の「dispatch_xxxxx」について記載します。

こちらも「dispatch_xxxxx」「dispatch_group_xxxxx」と2部構成になります。

前回、記載出来なかったdispatch_xxxxについて

サンプルソース
前回の【iPhoneアプリ】これを使えるようにならないと「マルチスレッド」について 実装編で
記載した「//スレッドの処理をこの部分に記載します。」部分に記載してください。

■dispatch_async_f

・非同期のタスク処理をblock構文ではなく、関数を利用したい場合

引数 説明
dispatch_queue_t ディスパチキューオブジェクト
void * 関数の引数:汎用ポインタ
dispactch_function 関数名


こんな感じのプログラムを書きます。

- (IBAction)thread_Button:(UIButton*)sender
{
  int int_obj = 20;
  dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  //dispatch_async_f実行
  dispatch_async_f(queue,(void *)int_obj,method_object);
}

//呼び出すメソッド
void method_object(void *context)
{
  NSLog(@"引数のvoid_ポインタ値:%d",(int)context);
}


結果はこんな感じです。

labo[19985:3d07] 引数のvoid_ポインタ値:20


■dispatch_sync_f

・同期のタスク処理をblock構文ではなく、関数を利用したい場合

引数 説明
dispatch_queue_t ディスパチキューオブジェクト
void * 関数の引数:汎用ポインタ
dispactch_function 関数名


こんな感じのプログラムを書きます。

- (IBAction)thread_Button:(UIButton*)sender
{
  int int_obj = 20;
  dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  //dispatch_sync_f実行
  dispatch_sync_f(queue,(void *)int_obj,method_object);
}

//呼び出すメソッド
void method_object(void *context)
{
  NSLog(@"引数のvoid_ポインタ値:%d",(int)context);
}


結果はこんな感じです。

labo[19994:60b] 引数のvoid_ポインタ値:20


ちなみに、下記のようにchar型の配列で処理を行うと
dispatch_async_f」「dispatch_sync_f」とでは表示が異なります。

そのため、「dispatch_async_f」の方では文字化けが起きるのでchar型の配列
使わない方がいいと思います。


こんな感じのchar型配列の処理プログラムを書きます。

- (IBAction)thread_Button:(UIButton*)sender
{
  char   char_arr[]  = "ABCDE";
    
  dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  //dispatch_async_f実行
  dispatch_async_f(queue,void_int,method_object);
  //dispatch_sync_f実行
  dispatch_sync_f(queue,void_int,method_object);
}


結果はこんな感じです。

labo[20044:1803] async_f 引数のvoid_ポインタ値:P΂ //文字化け発生!!
labo[20044:60b]  sync_f  引数のvoid_ポインタ値:ABCDE


■dispatch_after

・指定した時刻にblock構文によるタスク処理を実行させる場合

引数 説明
dispatch_time_t dispatch_timeもしくはdispatch_walltimeのオブジェクトを指定
dispatch_queue_t ディスパチキューオブジェクト
dispatch_block_t タスク処理が書かれたblock構文


こんな感じのプログラムを書きます。

NSLog(@"タスク実行前");
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_after(dispatch_time(DISPATCH_TIME_NOW,5*NSEC_PER_SEC),queue,^(void){
  NSLog(@"タスク実行後:呼び出されてから5秒後に処理されました。");
});


結果はこんな感じです。

19:22:07.113 labo[18333:60b] タスク実行前
19:22:12.576 labo[18333:3707] タスク実行後:呼び出されてから5秒後に処理されました。


■dispatch_after_f

・指定した時刻に関数を利用したい場合

引数 説明
dispatch_time_t dispatch_timeもしくはdispatch_walltimeオブジェクトを指定
(下記詳細)
dispatch_queue_t ディスパチキューオブジェクト
void * 関数の引数:汎用ポインタ
dispactch_function 関数名


こんな感じのプログラムを書きます。

- (IBAction)thread_Button:(UIButton*)sender
{
	 int int_obj = 20;
    
   dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
   dispatch_after_f(dispatch_time(DISPATCH_TIME_NOW,5 * NSEC_PER_SEC),queue,(void *)int_obj,method_object);

}

//呼び出すメソッド
void method_object(void *context)
{
    NSLog(@"タスク実行後:呼び出されてから5秒後に処理されました。");
    NSLog(@"引数のvoid_ポインタ値:%d",(int)context);
}


結果はこんな感じです。

19:56:40.632 labo[20020:1803] タスク実行後:呼び出されてから5秒後に処理されました。
19:56:40.634 labo[20020:1803] 引数のvoid_ポインタ値:20


▼dispatch_time

・dispatch_t型の指定した値からナノ秒単位の経過した時間を返します。

引数 説明
when dispatch_time_t型(unit64_t型)の値を指定
(下記詳細)
delta 待ち時間をdispatch_time_t 型(unit64_t型)を使ってナノ秒単位で指定


・dispatch_time_t 型 (uint64_t 型)

定数名 意味 利用方法
DISPATCH_TIME_NOW 現在時間 dispatch_timeのwhenなど、開始時間を指定時に利用
DISPATCH_TIME_FOREVER 時間制限無し dispatch_timeのdeltaなどで待ち時間を無制限時に利用
NSEC_PER_SEC 1秒あたりのナノ秒 1 秒として、目的のナノ秒数を算出します。例:5秒であれば、「NSEC_PER_SEC * 5」、0.5秒であれば「NSEC_PER_SEC / 2.0」と指定
NSEC_PER_MSEC 1ミリ秒あたりのナノ秒 1 ミリ秒として、目的のナノ秒を算出します。例:5ミリ秒であれば「NSEC_PER_MSEC * 5"」0.5 ミリ秒であれば「NSEC_PER_MSEC / 2.0」と指定
NSEC_PER_SEC 1秒あたりのマイクロ秒 1 秒として、目的のマイクロ秒を指定
NSEC_PER_USEC 1マイクロ秒あたりのナノ秒 1 マイクロ秒として、目的のナノ秒を算出します。例:5 マイクロ秒であれば「NSEC_PER_USEC * 5」0.5 マイクロ秒であれば「NSEC_PER_USEC / 2.0」と指定


▼dispatch_walltime

・「clock_gettime」の「timespec」に指定した時間からナノ秒単位の経過した
 時間を返します。

 ※もし、引数「*when」がNullの場合、gettimeofdayのが利用されます。
  実際に使ったところ、現在時刻でした。


引数 説明
*when struct timespecの値を指定
delta 待ち時間をdispatch_time_t 型(unit64_t型)を使ってナノ秒単位で指定


こんな感じのプログラムを書きます。

- (IBAction)thread_Button:(UIButton*)sender
{

  NSDate *date = [NSDate date];
  NSLog(@"TestThread_処理開始前");

  dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  dispatch_after(getDispatchTimebyDates(date),queue,^{
   NSLog(@"TestThread_block処理開始");
  });

}

//walltime設定関数
dispatch_time_t getDispatchTimebyDates(NSDate *date)
{
    
   NSTimeInterval interval;
   double second,subsecond;
   struct timespec time;
   dispatch_time_t milestone;
    
   interval = [date timeIntervalSince1970];
   subsecond = modf(interval,&second);

   time.tv_sec = second;
   time.tv_nsec = subsecond * NSEC_PER_SEC;
    
   //dispatch_walltimeに設定
   milestone = dispatch_walltime(NULL,NSEC_PER_SEC*5);
   //dispatch_walltimeを返す。
   return milestone;
}


結果はこんな感じです。

  labo[20272:60b] TestThread_処理開始前
  labo[20272:1807] TestThread_block処理開始


walltime設定関数」の解析が難しいと思いますので
解析した図を下記に用意しました。

▼処理解説

f:id:kassans:20140325160108p:plain

▼実際の値の流れ

f:id:kassans:20140325160708p:plain


■dispatch_apply

・指定した回数だけblock構文の処理を繰り返す。

引数 説明
iterations 繰り返す回数を指定
dispatch_queue_t ディスパチキューオブジェクト
dispatch_block_t タスク処理が書かれたblock構文、引数に現在のiterations回数が代入される


こんな感じのプログラムを書きます。

- (IBAction)thread_Button:(UIButton*)sender
{
   //レキシカルスコープ
   __block int i = 0;
   dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
   dispatch_apply(10,queue,^(size_t count){
      i = count;
      NSLog(@"dispatch_apply実行回数:%d",i);
   });
}


結果はこんな感じです。

labo[20404:60b]  dispatch_apply実行回数:0
labo[20404:1803] dispatch_apply実行回数:1
labo[20404:1803] dispatch_apply実行回数:3
labo[20404:60b]  dispatch_apply実行回数:2
labo[20404:1803] dispatch_apply実行回数:4
labo[20404:60b]  dispatch_apply実行回数:5
labo[20404:1803] dispatch_apply実行回数:6
labo[20404:60b]  dispatch_apply実行回数:7
labo[20404:1803] dispatch_apply実行回数:8
labo[20404:60b]  dispatch_apply実行回数:9

順番には処理されないが、asyncと同じではなく
メインスレッドと別スレッドで並列処理がされています。



■dispatch_apply_f

・指定した回数だけ、指定の関数の処理を繰り返す。

引数 説明
iterations 繰り返す回数を指定
dispatch_queue_t ディスパチキューオブジェクト
void * 関数の引数:汎用ポインタ
dispactch_function 関数名

※指定した関数の引数に、汎用ポインタ以外に現在のiterations回数が代入される


こんな感じのプログラムを書きます。

- (IBAction)thread_Button:(UIButton*)sender
{
    int int_obj = 20;
    dispatch_apply_f(10,queue,(void *)int_obj,apply_method);
}

void apply_method(void *context,size_t i)
{
    NSLog(@"引数のvoid_ポインタ値:%d",(int)context);
    NSLog(@"dispatch_apply実行回数:%d",(int)i);
}


結果はこんな感じです。

labo[20426:1803] 引数のvoid_ポインタ値:20
labo[20426:60b]  引数のvoid_ポインタ値:20
labo[20426:60b]  dispatch_apply実行回数:0
labo[20426:1803] dispatch_apply実行回数:1
labo[20426:60b]  引数のvoid_ポインタ値:20
labo[20426:60b]  dispatch_apply実行回数:2
labo[20426:60b]  引数のvoid_ポインタ値:20
labo[20426:60b]  dispatch_apply実行回数:4
labo[20426:1803] 引数のvoid_ポインタ値:20
labo[20426:1803] dispatch_apply実行回数:3
labo[20426:60b]  引数のvoid_ポインタ値:20
labo[20426:1803] 引数のvoid_ポインタ値:20
labo[20426:60b]  dispatch_apply実行回数:5
labo[20426:60b]  引数のvoid_ポインタ値:20
labo[20426:1803] dispatch_apply実行回数:6
labo[20426:1803] 引数のvoid_ポインタ値:20
labo[20426:60b]  dispatch_apply実行回数:7
labo[20426:1803] dispatch_apply実行回数:8
labo[20426:60b]  引数のvoid_ポインタ値:20
labo[20426:60b]  dispatch_apply実行回数:9

順番には処理されないが、asyncと同じではなく
メインスレッドと別スレッドで並列処理がされています。


■dispatch_once

・記載したblock構文を一度だけ実行する。

引数 説明
*predicate dispatch_once_tのポインタ
block タスク処理が書かれたblock構文


▼dispatch_once_t

・dispatch_onceで利用するオブジェクト
必ずstaicもしくは、グローバルでの変数を作成する。


こんな感じのプログラムを書きます。

  for(int i=0;i<10;i++){
    NSLog(@"処理回数:%d",i);
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
      NSLog(@"dispatch_once実行");
    });
  }
}


結果はこんな感じです。

labo[20456:60b] 処理回数:0
labo[20456:60b] dispatch_once実行
labo[20456:60b] 処理回数:1
labo[20456:60b] 処理回数:2
labo[20456:60b] 処理回数:3
labo[20456:60b] 処理回数:4
labo[20456:60b] 処理回数:5
labo[20456:60b] 処理回数:6
labo[20456:60b] 処理回数:7
labo[20456:60b] 処理回数:8
labo[20456:60b] 処理回数:9

【iPhoneアプリ】これを使いこなさないと「*(ポインタ)」について 汎用ポインタ編

今回も、「*(ポインタ)」についてです。


2部構成の汎用ポインタ編になります。
これは、便利なのですが使い方がよくわからなかった為、自分なりにまとめた形で
記載します。

汎用ポインタについて

汎用ポインタはこんな感じのポインタです。

■特徴
 ・ポインタ型のみ存在する
 ・ポインタ変数のみ使用可能
 ・「void *」のvoid型ポインタ
 
■使い方
 ・さまざまなデータ型に変換可能
 ・型指定なしでさまざまなデータ型を取得する関数を作成可能
 ・データ型のポインタ型であればどの型でも取得可能
 
■注意点
 ・参照するにはキャストして利用すること。
 ・データ型のサイズが異なるので表示結果の際、保証されない。
 ・void型の変数は存在しない為、void型のポインタ変数のみ利用できる。

色々調べた結果、以下のC言語のデータ型のみ利用可能。
※間違っていたら教えてください。

C言語のデータ型表

データ型名 変数名 32bitモデルのbit幅 32bitモデルのbit幅
整数型 short 16 16
整数型 unsigned short 16 16
整数型 int 32 32
整数型 long 32 64
整数型 unsigned 32 32
整数型 unsigned long 32 64
浮動小数点型 float 32 64
浮動小数点型 double 32 64
文字型 char 8 8
文字型 unsigned char 8 8
型なし void - -


汎用ポインタの実装

では、実際にプログラムを書いて実装してみます。


プログラムをこんな感じに書きます。

char object1 = 'A';
void *object2;
object2 = &object1;

NSLog(@"値1:%c",*(char *)object2);


下記、図はプログラムの解説になります。

f:id:kassans:20140319114331p:plain


次にすべてのデータ型のプログラムをこんな感じに書きます

■ViewController.m

#import "ViewController.h"

@implementation ViewController

- (void)viewDidLoad
{

    [super viewDidLoad];

    //変数宣言と実値を代入
    char   char_arr[]  = "ABCDE";
    char   char_obj    = 'A';
    short  short_obj   = 10;
    int    int_obj     = 20;
    long   long_obj    = 30;
    float  float_obj   = 10.5;
    double doublie_obj = 10.5;
    bool   bool_obj    = false;

    //void型ポインタ宣言
    void  *void_arry;
    void  *void_obj;
    void  *void_short;
    void  *void_int;
    void  *void_long;
    void  *void_float;
    void  *void_doublie;
    void  *void_bool;

    //実値のアドレスをvoid型ポインタ変数に代入
    void_arry    = &char_arr;
    void_obj     = &char_obj;
    void_short   = &short_obj;
    void_int     = &int_obj;
    void_long    = &long_obj;
    void_float   = &float_obj;
    void_doublie = &doublie_obj;
    void_bool    = &bool_obj;

    //void型ポインタ変数の表示
    NSLog(@"void_array値:%s",(char *)void_arry);
    NSLog(@"void_array値_要素1:%c",*(char *)void_arry++);
    NSLog(@"void_array値_要素2:%c",*(char *)void_arry++);
    NSLog(@"void_array値_要素3:%c",*(char *)void_arry++);
    NSLog(@"void_array値_要素4:%c",*(char *)void_arry++);
    NSLog(@"void_array値_要素5:%c",*(char *)void_arry++);
    NSLog(@"char値:%c",*(char *)void_obj);
    NSLog(@"short値:%d",*(short *)void_short);
    NSLog(@"int値:%d",*(int *)void_int);
    NSLog(@"long値:%ld",*(long *)void_long);
    NSLog(@"float値:%f",*(float *)void_float);
    NSLog(@"double値:%f",*(double *)void_double);
    NSLog(@"bool値:%d",*(bool *)void_bool);

}


void型ポイント変数をキャストして、以下のように値が表示されます。

labo[17175:60b] void_array値:ABCDE
labo[17175:60b] void_array値_要素1:A
labo[17175:60b] void_array値_要素2:B
labo[17175:60b] void_array値_要素3:C
labo[17175:60b] void_array値_要素4:D
labo[17175:60b] void_array値_要素5:E
labo[17175:60b] char値:A
labo[17175:60b] short値:10
labo[17175:60b] int値:20
labo[17175:60b] long値:30
labo[17175:60b] float値:10.500000
labo[17175:60b] double値:10.500000
labo[17175:60b] bool値:0


汎用ポインタの応用

汎用ポインタの応用として、
関数の引数にvoid型のポインタ変数を定義してみましょう。


こんな感じにプログラムを書きます。

■ViewController.m

#import "ViewController.h"

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    int int_obj = 20;
    void *void_int;
    void_int = &int_obj;
	
    void_pointer(void_int);

}

void void_pointer(void *context)
{
  NSLog(@"引数のvoid_ポインタ値:%d",*(int *)context);
}


結果は以下のように表示されます。

labo[17399:60b] 引数のvoid_ポインタ値:20


以上、「ポインタ変数」と「汎用ポインタ」の説明になります。
たまに、APIリファレンスの引数で「汎用ポインタ」が記載されています。

【iPhoneアプリ】これを使いこなさないと「*(ポインタ)」について ポインタ変数編

今回は、「*(ポインタ)」についてです。

やはり、ここも押さえとかないとObjective-c
使いこなすのは難しそうなので記載して行きます。

今回も2部構成で、ポインタ変数編汎用ポインタ編を記載します。

*(ポインタ)について

ポインタ変数とは、メモリーを管理する為の手法です。


通常の変数は、値を代入すると
以下のようにメモリー実数値が格納されます。


プログラムでこんな感じに書いて

int object1 = 100;
int object2 = 200;


格納イメージはこんな感じです。

f:id:kassans:20140318180424p:plain

次にポインタ変数を使って、値を代入してみます。
ここで「アドレス変数」と「ポインタ変数」を使って、以下のように記載します。


プログラムでこんな感じで書いて

int object1 = 100;
int *object2;
object2 = &object1;

NSLog(@"値1:%d",*object2);


宣言部分の説明になります。

f:id:kassans:20140318180422p:plain

この記述により
下記の図のように値が格納され、実数値を取り出す事が可能となります。

f:id:kassans:20140318182135p:plain



※また、このような書き方も出来るようですが、どのように
格納されるのか不明です。

f:id:kassans:20140318181021p:plain

ポインタ変数の特徴

ポインタ変数は「値の格納先アドレス」が格納されています。

その事により、「変数のアドレス」を「書き換える事」により、別のアドレスの値
参照することが可能となります。


以下の図ような感じなります。

f:id:kassans:20140318181011p:plain

ポインタ変数の応用

次に配列インスタンス時の場合ポインタ変数について記載して行きます。


配列のポインタ変数


通常の「ポインタ無し配列」の場合、以下のようにプログラムを記述します。

char object[] = "string";
NSLog(@"ポインタ無し_配列の値:%s",object);


次に「「ポインタあり配列」の場合、以下のようにプログラムを記述します。

char object[] = "string";
char *p_object;
p_object = &object[0];

//先頭のアドレスを参照
NSLog(@"配列の値_0:%s",p);

//参照先のアドレスを変更
NSLog(@"配列の値_0:%s",p++);
NSLog(@"配列の値_0:%s",p++);


このプログラムのイメージは以下のような感じです。


まずは、宣言部分のイメージ

f:id:kassans:20140318181008p:plain


次に値を表示部分の「参照先のアドレスを変更」時のイメージです。

f:id:kassans:20140318181013p:plain


また、以下のプログラムのように参照時に「*(ポインタ)」を付けると
そのアドレスの値のみを参照出来ます。

char object[] = "string";
char *p_object;
p_object = &object[0];

//先頭のアドレスを参照
NSLog(@"配列の値_0:%s",p);

//参照先のアドレスを変更
NSLog(@"配列の値_0:%s",*p++);
NSLog(@"配列の値_0:%s",*p++);


*(ポインタ)」を追加した表示部分の「参照先のアドレスを変更」時のイメージです。

f:id:kassans:20140318181014p:plain


インスタンス時のポインタ変数


クラスをインスタンスする際に以下のようなプログラムを書きます。

Object *obj;
obj = [[Object alloc] init];


インスタンス時のイメージです。


f:id:kassans:20140318181010p:plain


次回は、C言語で利用される「汎用ポインタ」について記載します。