カテゴリー別アーカイブ: program

プログラム書いてて気づいた事など。

[Unity][XML][C#]テキストデータを外部ファイル化するサンプル

[wp_ad_camp_1]

Unityのプロジェクトで日本語をコード内に記述してる事案があって、これを解消した時の構造をメモ。

gist::ogkslownin

TxtLib.cs

staticで定義したテキストデータをKeyValue形式で保持したライブラリを複数所持するクラス。
プロパティは次に説明するXMLPlistContainerクラスで定義される。

使い方はライブラリの種類と取得したい文字列と対になっているkeyを渡すことで文字列データを取得する。

XMLPlistContainer.cs

クラス生成時にファイルを読み込む。
Editor上でのみ、ファイルのタイムスタンプを参照して使用時に読み直しをする。
文字列を取得する際にはインデクサを用意して、key文字列を渡すことで得られる仕組み。

fruit_default.xml

ここのファイルにkeyと対になる文字列を定義しておく。
ファイルは同名にして各国分用意する。

サンプルではアプリケーションサーバを各国で分ける前提での設計なのだけれど、各国のファイルを平行して保持したいのであれば、XMLのファイル名を国別に用意し、XMLPlistCOntainer内での読み込み時の”_default_”を、引数として受けた国名文字列と差し替える記述をすれば対応可能になる。
C#で学ぶ偏微分方程式の数値解法

Photoshopで iOS App リリースに必要なアイコンを出力するスクリプト

iOSのアプリをリリースするにあたっていくつかのアイコン等が必要になります。
いちいちリサイズするのは面倒なので出力を自動化するスクリプトを作成しました。

やってること

  1. ドキュメントを新規作成。サイズは1024^2 (pix)
  2. リサイズしながら必要サイズのアイコン画像を指定の名前で保存。

サンプルと使い方

1024^2の解像度でオリジナルのアイコンを作成します。
アイコンを作成したらスクリプトを実行します。
以下のスクリプトをxx.jsxという名前で保存し、File->Script->Brows…から読み込むと実行されます。
保存先は最初に作ったアイコンが保存されているディレクトリなので、オリジナルpsdデータを保存しておく必要があります。
保存してないとエラーがでます。エラーの対処はしてません。

preferences.rulerUnits = Units.POINTS;
var saveName = activeDocument.path;
var doc;
createNewDocument();
savePngImgWithName("iTunesArtwork@2x");
changeImgSizeTo(512);
savePngImgWithName("iTunesArtwork");
changeImgSizeTo(144);
savePngImgWithName("Icon-72@2x");
changeImgSizeTo(114);
savePngImgWithName("icon@2x");	
changeImgSizeTo(72);
savePngImgWithName("Icon-72");
changeImgSizeTo(57);
savePngImgWithName("icon");
activeDocument.close(SaveOptions.DONOTSAVECHANGES);

function createNewDocument()
{
	doc = activeDocument.duplicate();
	w = activeDocument.width;
	h = activeDocument.height;
//	alert ( w+","+h );
	if( w != 1024 || h != 1024)
	{
		changeImgSizeTo(1024);
	}
}
function savePngImgWithName(name)
{
	var pathAndName = saveName +"/"+name+".png";
	var fileObj = new File(pathAndName);
	pngOpt = new PNGSaveOptions();
	pngOpt.interlaced = false;
	activeDocument.saveAs(fileObj,pngOpt,true, Extension.LOWERCASE);
}
function changeImgSizeTo(size)
{
	activeDocument.resizeImage(size,size);
}

Photoshop CS6のScript機能を使ってGradient(グラデーション)を描画する。

Photoshopでメタリックなテクスチャの制作方法を知りました。
が、キャンパスサイズによって感じがだいぶ変わってしまうので調度良いサイズを得るために何度か作り直していました。
これが徐々に面倒になりスクリプト化しようと思い立ち、何とか完成に。

テクスチャ製作手順

この本に載ってます。本をみなくても下に記述したスクリプトに記述してます。

ほめられデザイン事典 グラフィック・ワークス Photoshop & Illustrator
東 和毅 マスモリタロウ(MINIMUM)、 大西 真平 長場 雄
翔泳社
売り上げランキング: 44876

スクリプト製作でやったこと

  1. Photoshop上の操作をスクリプトに出力
  2. スクリプトを解析
  3. なんとなく抽象化

Photoshop上の操作をスクリプトに出力

Photoshopに”ScriptingListener.plugin”というプラグインを入れます。(Mac)
プラグイン(adobe)
インストール方法も日本語で提供されてます。

このプラグインを入れている間は、デスクトップ上に”ScriptingListenerJS.log”というログファイルが出力されます。
開くとConsoleが立ち上がり中身を表示してくれます。

ただし、プラグインが入っている間はずっとログを出力しつづけるのでファイルが肥大化します。
気づかない間に容量を圧迫しているなんてことがないように、不要な時はプラグインを削除します。

スクリプトを解析

やりた処理がわからない時はPhotoshop上で操作をし、それをLog上から解析することでスクリプトの記述方法がわかります。

解析には次の公式ドキュメントが助けになりました。
ADOBE PHOTOSHOP CS6 JAVASCRIPT SCRIPTING REFERENCE

ポイントになるのは以下の2点です。

ActionDescriptor

何をするにも登場します。
このオブジェクトに色々な情報を付加し、特定の操作を定義します。
形式はDictionaryで、keyとValueで格納します。

特徴は、情報をKeyと値セットで保持します。
保持の際にデータ型をメソッド名を以て指定します。

function addBlur(angle,pix)
{
var idMtnB = charIDToTypeID( "MtnB" );
    var desc170 = new ActionDescriptor();
    var idAngl = charIDToTypeID( "Angl" );
    desc170.putInteger( idAngl, angle );
    var idDstn = charIDToTypeID( "Dstn" );
    var idPxl = charIDToTypeID( "#Pxl" );
    desc170.putUnitDouble( idDstn, idPxl, pix );
executeAction( idMtnB, desc170, DialogModes.NO );
}

こんな感じで入れ子になって各操作や数値が定義されます。
また、”MtnB”等の4文字KeyはAdobe側で定義されているのですが、先のドキュメントに載ってないものばかり吐出されるので、どうにかして欲しいところです。
ここは気合いで。

ActionList

このオブジェクトはデータが時系列的に平行して存在する場合にまとめて定義します。
グラデーションの色データ等を格納するのに使います。

なんとなく抽象化

ログを解析すると似た様な箇所がけっこう出て来るので抽象化すると、構造の理解が深まって幸せになれます。
次に出来上がったものを示します。

サンプル

以下のスクリプトをUTF8形式のテキストファイルに貼付けて、”xxx.jsx”という名前で保存します。
Photoshop上からFile > Script > Browse…で保存したファイルを指定すると実行されます。


//create metalic texture

//Gradient
var width = activeDocument.width;
var height = activeDocument.height;
var startP = new pos(width,0);
var endP = new pos(0,height);
gradient(startP,endP);

//Noise
addNoise(15.0, true, true);

//Blur
//これくらいが調度良かった。
addBlur(0,width/20);

//Mono
hueAndSaturation(0,-100,0);

//data boj
function pos(arg_x,arg_y){
	this.x = arg_x;
	this.y = arg_y;
}

function hueAndSaturation(hue,saturation,lightness)
{
	//hue / saturation
var idHStr = charIDToTypeID( "HStr" );
    var desc = new ActionDescriptor();
	
    var idpresetKind = stringIDToTypeID( "presetKind" );
    var idpresetKindType = stringIDToTypeID( "presetKindType" );
    var idpresetKindCustom = stringIDToTypeID( "presetKindCustom" );
    desc.putEnumerated( idpresetKind, idpresetKindType, idpresetKindCustom );
	
    var idClrz = charIDToTypeID( "Clrz" );
	//Colorize (色彩の統一)
    desc.putBoolean( idClrz, false );
	
    var idAdjs = charIDToTypeID( "Adjs" );
        var list10 = new ActionList();
            var desc175 = new ActionDescriptor();
            var idH = charIDToTypeID( "H   " );
            desc175.putInteger( idH, hue );
            var idStrt = charIDToTypeID( "Strt" );
            desc175.putInteger( idStrt, saturation );
            var idLght = charIDToTypeID( "Lght" );
            desc175.putInteger( idLght, lightness );
        var idHsttwo = charIDToTypeID( "Hst2" );
        list10.putObject( idHsttwo, desc175 );
    desc.putList( idAdjs, list10 );
executeAction( idHStr, desc, DialogModes.NO );	
}
function addBlur(angle,pix)
{
var idMtnB = charIDToTypeID( "MtnB" );
    var desc170 = new ActionDescriptor();
    var idAngl = charIDToTypeID( "Angl" );
    desc170.putInteger( idAngl, angle );
    var idDstn = charIDToTypeID( "Dstn" );
    var idPxl = charIDToTypeID( "#Pxl" );
    desc170.putUnitDouble( idDstn, idPxl, pix );
executeAction( idMtnB, desc170, DialogModes.NO );
}

function addNoise( p,isGsn,isMono )
{
	var idAdNs = charIDToTypeID( "AdNs" );
		var noisDesc = new ActionDescriptor();
		var gaussId;
		if(isGsn)
		{
			gaussId = charIDToTypeID( "Gsn " );
		}else{
			gaussId = charIDToTypeID( "Unfr" );
		}
		var idDstr = charIDToTypeID( "Dstr" );
		noisDesc.putEnumerated( idDstr, idDstr, gaussId );

		var idNose = charIDToTypeID( "Nose" );
		var idPrc = charIDToTypeID( "#Prc" );

		//15% 
		noisDesc.putUnitDouble( idNose, idPrc, p );

		var idMnch = charIDToTypeID( "Mnch" );
		noisDesc.putBoolean( idMnch, isMono );

		var idFlRs = charIDToTypeID( "FlRs" );
		noisDesc.putInteger( idFlRs, 5450347 );
	executeAction( idAdNs, noisDesc, DialogModes.NO );	
	
}

function gradient(stratP,endP)
{
	 //各種情報入れとく場所
	var master = new ActionDescriptor();
	 putStartPosition (master, startP.x, startP.y);
	 putEndPosition (master, endP.x, endP.y);
	 //終点
	 //Enumerated
	var idType = charIDToTypeID( "Type" );
	var idGrdT = charIDToTypeID( "GrdT" );
	var idLnr = charIDToTypeID( "Lnr " );
	master.putEnumerated( idType, idGrdT, idLnr );

	 //Dthr
	var idDthr = charIDToTypeID( "Dthr" );
	master.putBoolean( idDthr, true );

	var idUsMs = charIDToTypeID( "UsMs" );
	master.putBoolean( idUsMs, true );

	var idGrad = charIDToTypeID( "Grad" );
	
	var idNm = charIDToTypeID( "Nm  " );
	var desc12 = new ActionDescriptor();
	  //Asset gradient
	desc12.putString( idNm, """$$$/DefaultGradient/Copper=Copper""" );
	
	var idGrdF = charIDToTypeID( "GrdF" );
	var idCstS = charIDToTypeID( "CstS" );
	desc12.putEnumerated( idGrdF, idGrdF, idCstS );
	
	var idIntr = charIDToTypeID( "Intr" );
	desc12.putDouble( idIntr, 4096.000000 );

	var idClrs = charIDToTypeID( "Clrs" );
	  //最初の色データオブジェクト

		var list2 = new ActionList();
			//RGBColorオブジェクト
			var colorObj1 = createRGBColorObj (151.000006, 70.000003, 26.000000);
			var desc13 = createRGBColorData(colorObj1,0,50);
			var idClrt = charIDToTypeID( "Clrt" );
		list2.putObject( idClrt, desc13 );

		//HSBColorオブジェクト
			/**/
			var colorObj2 = createHSBColorObj(21.115723,21.568627,98.431373);
			var desc15 = createHSBColorData(colorObj2, 1229, 50);
		list2.putObject( idClrt, desc15 );

		//色オブジェクト
			var colorObj3 = createRGBColorObj(108,46,22);
			var desc17 = createRGBColorData(colorObj3,3400,50);
		list2.putObject( idClrt, desc17 );
		   
		//色オブジェクト
			var colorObj4 = createRGBColorObj(239,219,205);
			var desc19 = createRGBColorData(colorObj4,4096,50);
		list2.putObject( idClrt, desc19 );
	desc12.putList( idClrs, list2 );
	
	//終了用リスト
		var list3 = new ActionList();
			var desc21 = new ActionDescriptor();
			putOpt (desc21, 100);
			putLctn (desc21, 0);
			putMdpn (desc21, 50)

			var idTrnS = charIDToTypeID( "TrnS" );
		list3.putObject( idTrnS, desc21 );

			var desc22 = new ActionDescriptor();
			putOpt(desc22,100.0);
			putLctn (desc22, 4096);
			putMdpn (desc22, 50);

			var idTrnS = charIDToTypeID( "TrnS" );
		list3.putObject( idTrnS, desc22 );
	
		var idTrns = charIDToTypeID( "Trns" );
	desc12.putList( idTrns, list3 );

	var idGrdn = charIDToTypeID( "Grdn" );
	master.putObject( idGrad, idGrdn, desc12 );
	
	//実行
	executeAction( idGrdn, master, DialogModes.NO );
}

function putOpt(targetObj,Double)
{
	var idOpct = charIDToTypeID( "Opct" );
	var idPrc = charIDToTypeID( "#Prc" );
	targetObj.putUnitDouble( idOpct ,idPrc ,Double );

}
function putLctn(targetObj,Integer)
{
	var idLctn = charIDToTypeID( "Lctn" );
	targetObj.putInteger( idLctn, Integer );
}
function putMdpn(targetObj,Integer)
{
	var idMdpn = charIDToTypeID( "Mdpn" );
	targetObj.putInteger( idMdpn, Integer  );
}

function createPositionDescriptor(x,y)
{
	var desc	= new ActionDescriptor();
	var idHrzn = charIDToTypeID( "Hrzn" );
	var idRlt = charIDToTypeID( "#Rlt" );
	desc.putUnitDouble( idHrzn, idRlt, x );//key, unitID, value
	var idVrtc = charIDToTypeID( "Vrtc" );
	var idRlt = charIDToTypeID( "#Rlt" );
	desc.putUnitDouble( idVrtc, idRlt, y);
	return desc;
}

function putStartPosition(obj,x,y)
{
	var pos = createPositionDescriptor(x,y);
	//開始位置のKey
	var idFrom = charIDToTypeID( "From" );
	//開始位置のunitID
	var idPnt = charIDToTypeID( "Pnt " );
	//開始位置オブジェクトをグラデーション実行オブジェクトに代入
obj.putObject( idFrom, idPnt, pos );	
}
function putEndPosition(obj,x,y)
{
	var pos = createPositionDescriptor(x,y);
	//開始位置のKey
	var idFrom = charIDToTypeID( "T   " );
	//開始位置のunitID
	var idPnt = charIDToTypeID( "Pnt " );
	//開始位置オブジェクトをグラデーション実行オブジェクトに代入
obj.putObject( idFrom, idPnt, pos );	
}

function createDescriptorWithGradientString(gradient)
{
	if(gradient == null)
	{
		//文字列型のデータを追加。"で囲ったプリセットのグラデーション
		gradient = """$$$/DefaultGradient/BlackWhite=Black, White""";
		gradient = """$$$/DefaultGradient/Copper=Copper""";
	}
	var desc= new ActionDescriptor();
	var idNm = charIDToTypeID( "Nm  " );
	desc.putString( idNm, gradient );
	return desc;
}


function createCMYKColorObj(c,m,y,k)
{
	var desc = new ActionDescriptor();
		var idCyn = charIDToTypeID( "Cyn " );
	desc.putDouble( idCyn, c);
	
		var idMgnt = charIDToTypeID( "Mgnt" );
	desc.putDouble( idMgnt, m );
	
		var idYlw = charIDToTypeID( "Ylw " );
	desc.putDouble( idYlw, y);
	
		var idBlck = charIDToTypeID( "Blck" );
	desc.putDouble( idBlck, k);
	return desc;
}

function createCMYKColorData( colorObj, Lctn)
{
	var  targetObj = new ActionDescriptor();
	var idClr = charIDToTypeID( "Clr " );
	var idCMYC = charIDToTypeID( "CMYC" );
	targetObj.putObject( idClr, idCMYC, colorObj );
	   
		var idType = charIDToTypeID( "Type" );
		var idClry = charIDToTypeID( "Clry" );
		var idUsrS = charIDToTypeID( "UsrS" );
	targetObj.putEnumerated( idType, idClry, idUsrS );
	   
		var idLctn = charIDToTypeID( "Lctn" );
	targetObj.putInteger( idLctn, Lctn );
	   
		var idMdpn = charIDToTypeID( "Mdpn" );
	targetObj.putInteger( idMdpn, 50 );
	return targetObj;
}
function createRGBColorObj(r,g,b)
{
	var desc = new ActionDescriptor();
	var idRd = charIDToTypeID( "Rd  " );
	desc.putDouble( idRd, r );
	var idGrn = charIDToTypeID( "Grn " );
	desc.putDouble( idGrn, g);
	var idBl = charIDToTypeID( "Bl  " );
	desc.putDouble( idBl, b);
	return desc;
}
function createRGBColorData(colorObj,Lctn,Mdpn)
{
	var desc = new ActionDescriptor();
	var idClr = charIDToTypeID( "Clr " );
	var idRGBC = charIDToTypeID( "RGBC" );
	desc.putObject( idClr, idRGBC, colorObj );
	var idType = charIDToTypeID( "Type" );
	var idClry = charIDToTypeID( "Clry" );
	var idUsrS = charIDToTypeID( "UsrS" );
	desc.putEnumerated( idType, idClry, idUsrS );
	putLctn (desc, Lctn);
	putMdpn (desc, Mdpn);
	return desc;
}


function createHSBColorObj(h,s,b)
{
	var desc = new ActionDescriptor();
	
	var idH = charIDToTypeID( "H   " );
	var idAng = charIDToTypeID( "#Ang" );
	desc.putUnitDouble( idH, idAng, h);

	var idStrt = charIDToTypeID( "Strt" );
	desc.putDouble( idStrt, s );

	var idBrgh = charIDToTypeID( "Brgh" );
	desc.putDouble( idBrgh, b);
	
	return desc;
}

function createHSBColorData(HSBObj,Lctn,Mdpn)
{
	var desc = new ActionDescriptor();
	
	var idClr = charIDToTypeID( "Clr " );
	var idHSBC = charIDToTypeID( "HSBC" );
	desc.putObject( idClr, idHSBC, HSBObj );

	var idType = charIDToTypeID( "Type" );
	var idClry = charIDToTypeID( "Clry" );
	var idUsrS = charIDToTypeID( "UsrS" );
	desc.putEnumerated( idType, idClry, idUsrS );
	
	putLctn(desc,Lctn);
	putMdpn (desc, Mdpn);
	return desc;
}

function blackGradient()
{
	
	//グラデーションを実行するオブジェクトを生成
var master = new ActionDescriptor();
	
	putStartPosition(master,0.0,0.0);
	putEndPosition (master, 600, 0.0);

		var idType = charIDToTypeID( "Type" );
		var idGrdT = charIDToTypeID( "GrdT" );
		var idLnr = charIDToTypeID( "Lnr " );
master.putEnumerated( idType, idGrdT, idLnr );
	
		var idDthr = charIDToTypeID( "Dthr" );
master.putBoolean( idDthr, true );
	
		var idUsMs = charIDToTypeID( "UsMs" );
master.putBoolean( idUsMs, true );//bool 型のデータを追加
	
		//ここからGradient Data
		var gradientData =  createDescriptorWithGradientString(); //new ActionDescriptor();
		
			var idIntr = charIDToTypeID( "Intr" );
gradientData.putDouble( idIntr, 4096.000000 );
//gradientData.putDouble( idIntr, 0.000000 );
		
		//
		var colorList = new ActionList();
			//black color obj
			var black = createCMYKColorObj(75.02,68.01,67,90.19);	
			var colorData1 =  createCMYKColorData(black,0);

			var idClrt = charIDToTypeID( "Clrt" );
			colorList.putObject( idClrt, colorData1 );

			var white = createCMYKColorObj(0,0,0,0);
			var colorData2 = createCMYKColorData(white,4096);
			colorList.putObject( idClrt, colorData2 );

		var idClrs = charIDToTypeID( "Clrs" );
		gradientData.putList( idClrs, colorList );

		var list5 = new ActionList();

			var desc34 = new ActionDescriptor();
			putOpt(desc34,100.0);
			putLctn(desc34,0);
			putMdpn(desc34,50);

			var idTrnS = charIDToTypeID( "TrnS" );
		list5.putObject( idTrnS, desc34 );
		
			var desc35 = new ActionDescriptor();
			putOpt(desc35,100.0);
			putLctn (desc35, 4096);
			putMdpn (desc35, 50);
				
			var idTrnS = charIDToTypeID( "TrnS" );
		list5.putObject( idTrnS, desc35 );

			var idTrns = charIDToTypeID( "Trns" );
		gradientData.putList( idTrns, list5 );

	var idGrad = charIDToTypeID( "Grad" );//key
	var idGrdn = charIDToTypeID( "Grdn" );//unitID
	master.putObject( idGrad, idGrdn, gradientData );
executeAction( idGrdn, master, DialogModes.NO );
}

応用

色オブジェクト(次のサンプル部分)をgradient()に追加して複雑なグラデーションを作成してみると面白いかもしれません。

//色オブジェクト
	var colorObj3 = createRGBColorObj(108,46,22);//createRGBColorObj(r,g,b);
	var desc17 = createRGBColorData(colorObj3,3400,50);
	list2.putObject( idClrt, desc17 );

JavaScript 第6版

UITabBarControllerのTabItem画像が表示されない!

UITabBarControllerを利用して画像が表示されなくてこまりました。


Tabbar Doesn't appear.

原因は画像データには alpha channel を含んでないとだめだそうで、よくよく調べるとalphaをグレースケール表示しているようでした。

例のごとく、
stackoverflow:Tab bar image icon doesn’t appear

Photoshopでalphaチャンネル付き画像データを作る

※Photosho CS6(Mac)
せっかくなのでPhotoshopを使って alpha 含むTabBarItem用のpng作成手順を残します。
alphaChannel000
最終的に Script > Export Layers to Files…を行うので、画像のようにレイヤー単位で画像を保持させておきます。
一番上のレイヤーのブラジル国旗をベースに作成をします。
alphaChannel001
Layer > Layer Mask > Revel all で真っ白なレイヤーマスクを追加。

alphaChannel002
Window > Channel で Channel を表示。Layer Maskを追加しているので(画像では黒だけど)白いチャンネルが表示され、非表示になってる。
Greenのチャンネルをコピーし、全体を非表示にしてから、Alphaだけを可視化(目のマーク)にする。
alphaChannel003
可視化したらGreenのチャンネルをペーストする。

alphaChannel004
ペーストしたら、可視状態をalphaを不可視化してRGBを可視化する。

alphaChannel005
完成はご覧の通り。

Screen Shot 0024-12-04 at 20.16.57
やったね!

ほめられデザイン事典 グラフィック・ワークス Photoshop & Illustrator

iAdを固定位置にするサンプル

iAdの位置固定方法を調べて最適解を得たのでメモ。

やっていること

iAdを表示するviewを作成。
iAdのviewを固定位置にするためだけのUIViewを生成。
UIViewはスクロールの度に走る次のイベントで位置を設定しなおす。

- (void)scrollViewDidScroll:(UIScrollView *)

サンプル

- (void)viewDidAppear:(BOOL)animated{
   
    [super viewDidAppear:animated];
    //for iAd initialization
    //tmp view

    // iAdViewContainerはUIViewクラスのメンバ。
    if(iAdViewContainer_ == nil){
        iAdViewContainer_ = [[UIView alloc]initWithFrame:self.view.frame];
        [self.view addSubview:iAdViewContainer_];
       
        //adView_ はADBannerViewクラスのメンバ
        adView_ = [[ADBannerView alloc] initWithFrame:CGRectMake(0.0, 367.0, 320.0, 50.0)];
        adView_.currentContentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;
        [iAdViewContainer_ addSubview:adView];
    }   
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    [self resetIAdPosition];
}
- (void)resetIAdPosition
{
    [iAdViewContainer_ setFrame:CGRectMake(
                                           self.tableView.contentOffset.x,
                                           self.tableView.contentOffset.y,
                                           0,0)];
    [self.view bringSubviewToFront:iAdViewContainer_];
}

解説

画面下部に固定させたいので、iAd自身とそれを固定位置で保持するviewの2つを生成する。
片方は色々なところで参照するのでメンバ変数として定義しておく。
サンプル上ではiAdViewController_がUIView型のメンバだ。

viewDidApearイベント時にで、画面に指定のコントローラが保持するViewが出現した際にiAdを生成する。

補足

tableView:titleForHeaderInSection:で項目名や、
tableView:titleForFooterInSection:で説明文を入れていると、
viewが手前に配置されてしまい、iAdのバナーよりもうしろになる。
これを回避するために、奥に成ってしまっているiAdのz-indexを手前に描画されるようにresetIAdPositionでviewのソートをさせている。
これで手前側に移動させることができる。

ただし、推奨とされている表示方法はもう一段階踏み込まなければ成らない。
それは表示可能になった際にはじめて表示するというもの。
オブジェクトとして生成してから表示が可能になるまでに時間がかかるので、その間は画面外にでも配置しておくべき。
これは別途記事にする。

参考

サルにもできるiPhoneアプリの作り方iAdを設置してみよう! その1
※ソースはほとんどここのものがベース。
StackOverFlow:How to set iPhone UI View z index?

iOS5プログラミングブック
加藤 寛人 吉田 悠一 藤川 宏之 西方 夏子 関川 雄介 高丘 知央
インプレスジャパン
売り上げランキング: 2989

[XCode4][UIKit]UITableVieCellをオリジナルのXibを使用して表示する

ここに凄くシンプルな方法が載っていたのでまとめ。
http://stackoverflow.com/で載っていたサンプル

用意するもの

  • Cell.h
  • Cell.m
  • Cell.xib
  • MasterViewController.h
  • MasterViewController.m

前提として・・・

Cellは基本的に表示してる領域+前後いくつか分のViewしか持たないのでCellそのものにデータ保持をさせるのは危険。

やっていること

独立したUITableViewCellクラス専用に1つのXibを持たせる。
Cell自身がXibを呼び出すので、他のサイトで載っているようなController側が保持するやりかたのように複雑風にならない。

Cell.h

#import 

@interface Cell : UITableViewCell
{
    NSNumber* num_;
@private
   IBOutlet UILabel* label1_;
   IBOutlet UILabel* label2_;
   IBOutlet UIImageView* icon_;
}
@property (nonatomic,strong) UILabel* label1;
@property (nonatomic,strong) UILabel* label2;
@property (nonatomic,strong) UIImageView* icon;

+ (Cell*)cellFromNibNamed:(NSString *)nibName;
@end

Cell.m

#import "Cell.h"
@implementation Cell
@synthesize label1 = label1_;
@synthesize label2 = label2_;
@synthesize icon = icon_;

+ (Cell *)cellFromNibNamed:(NSString *)nibName {
    NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:NULL];
    NSEnumerator *nibEnumerator = [nibContents objectEnumerator];
    Cell *customCell = nil;
    NSObject* nibItem = nil;
    while ((nibItem = [nibEnumerator nextObject]) != nil) {
        if ([nibItem isKindOfClass:[Cell class]]) {
            customCell = (Cell *)nibItem;
            break; // we have a winner
        }
    }
    return customCell;
}
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    NSLog(@"%s",__func__);
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code
    }
    return self;
}

+ (Cell *)cellFromNibNamed:(NSString *)nibName について

このクラスメソッドでは何でも格納ObjectNSArray型のnibContentsにXibを読み込んで格納し、列挙型NSEnumeratorを生成。
Xib内に独自Cell用のnibがあったら返してもらい、それを以てCellとし、列挙を離脱。
最後にCellを返して終了する、という流れ。

MasteViewController.m

セルの生成

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    cell = [tableView dequeueReusableCellWithIdentifier:@"orgCell"];
    if (cell == nil) {
        cell = (Cell *)[Cell cellFromNibNamed:@"Cell"];
        cell.label1.text = @"test";
    }
    return cell;
}

ここでは先のCellで定義したNibを読み込んでViewを生成するクラスメソッドを呼び出して格納している。
label1.textはviewに載っているLabelにIBOutletで接続したUILabelへの接続。独自に作ったXibに合わせて変更を。

また、Cellにコントローラを埋める場合はCellの使い回しをセルの種類単位で分けないとぐちゃぐちゃになるとの事。

セルの高さ指定

必ずFloat型の数値を返しておくこと。

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"%s",__func__);
    return 100.0;
}

セル選択時の表現の変更

セルを生成しなおしたりできる。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"%s",__func__);
}

セルの選択解除時の変更

変更をデフォルトに戻しておく。

-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
    NSLog(@"%s",__func__);
}

XibのIBOutletの設定

File’sOwnerのCustomClassの項目はMasterViewControllerにしておく。
※これは記述無しでも駆動する。記述が無い場合はデフォルトの値が入るので、Cell
Cell側のCustomClassの項目はCellにする。
Cells'Class

IBOutlet付きのメンバはCell下のLabel – Label1等に直接接続する。
IBOutlet

デフォルトのプロパティに準拠

UITableViewCellはデフォルトでUILabelを複数保持している。
これらのプロパティ名はtextLabelとdetailTextLabelなのでこれらの既存プロパティをメンバ変数と一緒に扱う事で上書きができる。無為にプロパティを増やさなくて済む。

サンプル

Cell.h

@interface Cell : UITableViewCell
{
    NSNumber* num_;
@private
    IBOutlet UILabel* label1_;
    IBOutlet UILabel* label2_;
    IBOutlet UIImageView* icon_;
    IBOutlet UILabel* detailTextLabel_;//既存プロパティ用に追加。
    IBOutlet UILabel* textLabel_;//既存プロパティ用に追加。
}

Cell.m

@synthesize detailTextLabel = detailTextLabel_;
@synthesize textLabel = textLabel_;

これで既存プロパティと共通化させる事が出来た。

下の画像のセル中央部分がオリジナルのプロパティ。右側がデフォルトのプロパティを利用した表示。
Screen Shot 0024-09-09 at 13.51.26

今更きけないUILabelの基本まとめ

概要

UILabelはUIViewを継承したクラス。
固定された内容のテキストを画面に貼付けるのに使う。
生成したら必ずどこぞのコントローラ下のViewにaddSubviewする。

UILabelTest

プロパティ

設定できるプロパティは以下の通り。

text

  • NSStringでパラメータ付与。
  • ラベル内に表示する文字列を指定する。

font

 

  • UIFontで指定。
  • フォントの種類を指定。フォントオブジェクトはその章を参照。
  •  

textColor

   

  • UIColorでパラメータ付与。
  • フォントの色を変える。
  •  

lineBreakMode

   

  • UILineBreakMode定数を指定する。
  • 文字数オーバー時の表現方法を指定。
  •  

enabled

   

  • BOOL指定。
  • グレー反転させて使用不可表現を行う。
  •  

adjustsFontSizeToFitWidth

   

  • BOOL指定。
  • textで指定した文字列がラベルの矩形内に納まる様にアジャストするか否かを指定する。
  • これをYESニシタバアイハlineBreakModeが無効になる。
  •  

baselineAdjustment

   

  • UIBaselineAdjustmentを文字列定数で指定。
  •  

minimumFontSize

   

  • CGFloatで指定。
  • 次に記述するnumberOfLinesが1の時のみ効果が出る。
  •  

numberOfLines

   

  • NSInteger指定。
  • textで指定された文字列を表示する限界の行数を指定する。
  •  

highlightedTextColor

   

  • UIColor指定。
  • ハイライトされた際の文字色を指定する。
  •  

highlighted

   

  • BOOL指定
  • ハイライトするか否かを指定する。
  •  

shadowColor

   

  • UIColor指定。
  • highlightedが有効だと
  •  

shadowOffset

   

  • CGSize指定。
  • CGSizeはCGFloat型のwidthとheightの2部構成。CGSizeMake(w,h)で作成。
  •  

userInteractionEnabled

   

  • BOOL指定。
  • タッチの検出をするか否か。しない、がデフォ。
  •  

メソッド一覧

    drawTextInRect:

    • このメソッドは直接呼ばない方が良い。継承したサブクラスのデフォルトの振舞で描画したい時に呼ばれるべきだ。
    • このメソッドが呼ばれる時、現在の描画コンテキスト(デフォルトの環境とテキストの色で)の設計が完了する。
    • Overrideしたメソッドではsuper使って同名メソッドを発動させよう。

    textRectForBounds:limitedToNumberOfLines:

       

    • ラベルのテキストの矩形(CGRect)を返す。
    • parameter
      • bounds(CGRect)
      •      

        • レシーバの矩形を渡す
      • numberOfLines:(NSInteger)
      •          

        • 最大行数を渡す
    • このメソッドは直接呼ぶべきではない。レシーバに指定した矩形に何かしらの計算を伴う動作をさせる前に、継承したサブクラスがOverrideしたメソッドから呼ぶべきだ。
    • 最大行数を指定するnumberOfLinesパラメータを使って高さの上限を返される矩形に指定できる。
    • メソッドを呼ぶためにはsizeToFitか、sizeThatFitsの呼び出しが先だ。
    • UITableViewCellオブジェクト内のUILabel、またはサイズ指定のないUILabelはセルの寸法ベースのサイズが適用される。
    •    

    UILineBreakModeについて

    矩形に対する文字列幅がオーバーした際の表現方法を指定する。
    もともと行数指定をしてた場合は矩形幅がたらなくなるところまでは大凡共通した仕様で改行が行われる。
    UILineBreakModeCharacterWrapは例外で、Word間で自動改行ではなく、たらなくなった時点で改行が行われるので1単語を切ることになるので注意が必要。
    UILabel_Preview

    typedef enum {
       UILineBreakModeWordWrap = 0,
       UILineBreakModeCharacterWrap,
       UILineBreakModeClip,
       UILineBreakModeHeadTruncation,
       UILineBreakModeTailTruncation,
       UILineBreakModeMiddleTruncation, } UILineBreakMode;
    

    サンプル

    このサンプルを実行すると本記事のトップで表示した画像とおなじViewになる。

    - (void)viewDidLoad
    {
        NSLog(@"%s",__func__);
        [super viewDidLoad];
        
        float margine = 5;
        float y = 5;
        float h = 70;
        CGRect rect1 = CGRectMake(10,y,300,h);
        UILabel* label_UILineBreakModeWordWrap = [[UILabel alloc]initWithFrame:rect1];
        label_UILineBreakModeWordWrap.lineBreakMode = UILineBreakModeWordWrap;
        label_UILineBreakModeWordWrap.text = @"label_UILineBreakModeWordWrapnthis is label_UILineBreakModeWordWrap this is label_UILineBreakModeWordWrap this is label_UILineBreakModeWordWrap this is label_UILineBreakModeWordWrap";
        label_UILineBreakModeWordWrap.font = [UIFont systemFontOfSize:[UIFont smallSystemFontSize]];
        label_UILineBreakModeWordWrap.textAlignment = UITextAlignmentLeft;
        label_UILineBreakModeWordWrap.numberOfLines = 3;
        [self.view addSubview:label_UILineBreakModeWordWrap];
        
        y += h + margine;
        
        CGRect rect2 = CGRectMake(10,y,300,h);
        UILabel* label_UILineBreakModeTailTruncation = [[UILabel alloc]initWithFrame:rect2];
        label_UILineBreakModeTailTruncation.lineBreakMode = UILineBreakModeTailTruncation;
        label_UILineBreakModeTailTruncation.text = @"label_UILineBreakModeTailTruncationnthis is label_UILineBreakModeTailTruncation this is label_UILineBreakModeTailTruncation this is label_UILineBreakModeTailTruncation this is label_UILineBreakModeTailTruncation";
        label_UILineBreakModeTailTruncation.font = [UIFont systemFontOfSize:[UIFont smallSystemFontSize]];
        label_UILineBreakModeTailTruncation.textAlignment = UITextAlignmentLeft;
        label_UILineBreakModeTailTruncation.enabled = NO;
        label_UILineBreakModeTailTruncation.adjustsFontSizeToFitWidth = YES;
        label_UILineBreakModeTailTruncation.baselineAdjustment = UIBaselineAdjustmentAlignBaselines;//UIBaselineAdjustmentNone;//UIBaselineAdjustmentAlignCenters;//
        label_UILineBreakModeTailTruncation.numberOfLines = 3;
        label_UILineBreakModeTailTruncation.highlighted = YES;
        label_UILineBreakModeTailTruncation.shadowColor = [UIColor redColor];
        label_UILineBreakModeTailTruncation.shadowOffset = CGSizeMake(3.0, 2.0);
        [self.view addSubview:label_UILineBreakModeTailTruncation];
    
        y += h + margine;
    
        CGRect rect3 = CGRectMake(10,y,300,h);
        UILabel* label_UILineBreakModeMiddleTruncation = [[UILabel alloc]initWithFrame:rect3];
        label_UILineBreakModeMiddleTruncation.lineBreakMode = UILineBreakModeMiddleTruncation;
        label_UILineBreakModeMiddleTruncation.text = @"label_UILineBreakModeMiddleTruncationnthis is label_UILineBreakModeMiddleTruncation this is label_UILineBreakModeMiddleTruncation this is label_UILineBreakModeMiddleTruncation";
        label_UILineBreakModeMiddleTruncation.font = [UIFont systemFontOfSize:[UIFont smallSystemFontSize]];
        label_UILineBreakModeMiddleTruncation.textAlignment = UITextAlignmentLeft;
        label_UILineBreakModeMiddleTruncation.numberOfLines = 3;
        label_UILineBreakModeMiddleTruncation.highlighted = NO;
        label_UILineBreakModeMiddleTruncation.highlightedTextColor = [UIColor blueColor];
        label_UILineBreakModeMiddleTruncation.shadowColor = [UIColor redColor];
        label_UILineBreakModeMiddleTruncation.shadowOffset = CGSizeMake(3.0, 2.0);
    
        [self.view addSubview:label_UILineBreakModeMiddleTruncation];
        
        y += h + margine;
    
        CGRect rect4 = CGRectMake(10,y,300,h);
        UILabel* label_UILineBreakModeHeadTruncation = [[UILabel alloc]initWithFrame:rect4];
        label_UILineBreakModeHeadTruncation.lineBreakMode = UILineBreakModeHeadTruncation;
        label_UILineBreakModeHeadTruncation.text = @"label_UILineBreakModeHeadTruncationnthis is label_UILineBreakModeHeadTruncation this is label_UILineBreakModeHeadTruncation this is label_UILineBreakModeHeadTruncation";
        label_UILineBreakModeHeadTruncation.font = [UIFont systemFontOfSize:[UIFont smallSystemFontSize]];
        label_UILineBreakModeHeadTruncation.textAlignment = UITextAlignmentLeft;
        label_UILineBreakModeHeadTruncation.numberOfLines = 3;
        label_UILineBreakModeHeadTruncation.highlighted = YES;
        label_UILineBreakModeHeadTruncation.highlightedTextColor = [UIColor blueColor];
        label_UILineBreakModeHeadTruncation.shadowColor = [UIColor redColor];
        label_UILineBreakModeHeadTruncation.shadowOffset = CGSizeMake(3.0, 2.0);
    
        [self.view addSubview:label_UILineBreakModeHeadTruncation];
    
        y += h + margine;
    
        CGRect rect5 = CGRectMake(10,y,300,h);
        UILabel* label_UILineBreakModeClip = [[UILabel alloc]initWithFrame:rect5];
        label_UILineBreakModeClip.lineBreakMode = UILineBreakModeClip;
        label_UILineBreakModeClip.text = @"label_UILineBreakModeClipnthis is label_UILineBreakModeClip this is label_UILineBreakModeClip this is label_UILineBreakModeClip this is label_UILineBreakModeClip";
        label_UILineBreakModeClip.font = [UIFont systemFontOfSize:[UIFont smallSystemFontSize]];
        label_UILineBreakModeClip.textAlignment = UITextAlignmentLeft;
        label_UILineBreakModeClip.numberOfLines = 3;
        label_UILineBreakModeClip.userInteractionEnabled = NO;
        [label_UILineBreakModeClip textRectForBounds:CGRectMake(50,y,100,h) limitedToNumberOfLines:0];
        [self.view addSubview:label_UILineBreakModeClip];
    
        y += h + margine;
    
        CGRect rect6 = CGRectMake(10,y,300,h);
        UILabel* label_UILineBreakModeCharacterWrap = [[UILabel alloc]initWithFrame:rect6];
        label_UILineBreakModeCharacterWrap.lineBreakMode = UILineBreakModeCharacterWrap;
        label_UILineBreakModeCharacterWrap.text = @"label_UILineBreakModeCharacterWrapnthis is label_UILineBreakModeCharacterWrap this is label_UILineBreakModeCharacterWrap this is label_UILineBreakModeCharacterWrap this is label_UILineBreakModeCharacterWrap";
        label_UILineBreakModeCharacterWrap.font = [UIFont systemFontOfSize:[UIFont smallSystemFontSize]];
        label_UILineBreakModeCharacterWrap.textAlignment = UITextAlignmentLeft;
        label_UILineBreakModeCharacterWrap.numberOfLines = 3;
        label_UILineBreakModeCharacterWrap.userInteractionEnabled = YES;
        [label_UILineBreakModeCharacterWrap drawTextInRect:CGRectMake(10,y,100,h)];
        [self.view addSubview:label_UILineBreakModeCharacterWrap];
    }
    

    詳解 Objective-C 2.0 第3版

    Objective-C プログラマーズバイブル

[C#]ListをRemoveAll( c => !c.MoveNext());する意味のまとめ

※いろいろと間違っていたのを修正。

数ヶ月前に参加したUnity仙人のセミナー、Unityで覚えるC#のサンプルで挙動がよくわからなかったもののまとめ。

サンプルは前述のスライドの56ページ。

ここで何が起こってるのかをまとめる。

まずListの言語仕様を整理

参考:http://www.atmarkit.co.jp/fdotnet/special/generics01/generics01_02.html

ListGenericClassは内容物の型を宣言する形式のArrayListクラス(のようなもの)。

Listという形で使用する。

ArrayListもListGenericも共に.Add()で内容を追加する。

この処理速度はListGenericの方が上。

理由はArrayListの場合はオブジェクトに変換するボックス化処理が挟まるから。

ジェネリッククラスの記述方法

参考:http://www.atmarkit.co.jp/fdotnet/special/generics01/generics01_03.html

山括弧内の型指定をTにすることで型を後付けにして汎用化できる。

ただ、複数の型を混在させる事が出来るわけではない。これをしたいのであればDictionaryClassを使用する。

Whereキーワード

型指定はTにしたいけれどもクラスであることは確実だったり、構造体であることが確実であったりと条件を幾分追加するキーワードで先の参考に示したページにその一覧が記述されている。

class MyGenericClass1 where T : struct {
  // 制約:Tは構造体
}

class MyGenericClass2 where T : class {
  // 制約:Tはクラス
}

class MyGenericClass3 where T : new() {
  // 制約:Tはインスタンス化可能
}

class MyGenericClass4 where T : MyOtherClass {
  // 制約:TはMyOtherClassクラスを継承
}

class MyGenericClass5 where T : IMyInterface {
  // 制約:TはIMyInterfaceインターフェイスを実装
}

class MyGenericClass6 where T : U {
  // 制約:Tは別の型パラメータUを継承
}

//////////////////////////////////////////////////
class MyOtherClass {
  // とあるクラス
}

interface IMyInterface {
  // とあるインターフェイス
}

また、複数の制約も可能ということなので試してみました。

class MyGenericClass where T:class,new()

こんな風にコロンで連結すれば良いです。

ゲームだと、出現したゴブリンとホフゴブリンとゴブリンアーチャー全員がゴブリンパンチ打てるよーって状況で全員がゴブリンパンチを採択するとかで使える。

例が限定的すぎるけれども。

ジェネリックに限らず、こういった書き方ができるのはC#の強み。

  public T this[int index] {
    get {
      return _list[index];
    }
    set {
      _list[index] = value;
    }
  }

で、ジェネリックについて整理したけどList型と必ずしも関連しないという事を注意したい。

List型はIEnumerableなのでforeachが使えるけれども、

前述した例だと独自実装なのでIEnumeratorを実装しておらず、foreachが使えない。

なんということでしょう・・・。

ListクラスのRemoveAllを理解する

RemoveAllメソッドは、特定の条件に一致する要素だけ削除する際に使用するメソッド。

RemoveAllの引数として、条件を判別するメソッドのハンドラ渡し、Trueが返る場合は削除を行う。

そこまでのサンプル。

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class genericRemoveAll : MonoBehaviour {

     // Use this for initialization
     void Start () {
          List<orgString> stringList = new List<orgString>();

          for( int i =0 ; i < 10; i++){
               orgString tmp = new orgString( "string:"+i );
               stringList.Add( tmp );
          }

          stringList.RemoveAll( Method );
          foreach(orgString o in stringList)
          {
                o.Method();
          }

     }
     bool Method(orgString o){
          return o.str == "string:3";
     }
     // Update is called once per frame
     void Update () {

     }
     public class orgString{
          public string str;
          public orgString(string s){
               this.str = s;
          }
          public void Method()
          {
               Debug.Log("at method :"+this.str);
          }
     }
}

相変わらず起動確認はUnityで。

RemoveAllの中身をラムダ式にするとこうなる。

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class genericRemoveAll : MonoBehaviour {

     // Use this for initialization
     void Start () {
          List<orgString> stringList = new List<orgString>();

          for( int i =0 ; i < 10; i++){
              orgString tmp = new orgString( "string:"+i );
              stringList.Add( tmp );
          }
          stringList.RemoveAll( s => s.str == "string:3" );
          foreach(orgString o in stringList)
          {
                o.Method();
          }

     }
     public class orgString{
          public string str;
          public orgString(string s){
               this.str = s;
          }
          public void Method()
          {
               Debug.Log("at method :"+this.str);
          }
     }
}

参考:http://www.atmarkit.co.jp/fdotnet/dotnettips/815listremove/listremove.html

ラムダ式をおさらい

ラムダ式はEventHandlerを省略したデリゲートをさらに省略した記述方式。

なのでラムダ式には左辺と右辺があり、左辺はdelegateとして呼び出されるメソッドのparameterが入り、右辺には式か文が入る。

左辺の記述は()にくくられていなければならないが、parameterが単一の場合は省略可能。

右辺の記述が式の場合、セミコロンで閉じない。

右辺の記述が文の場合、{ 文; 文; 文; }と記述し、{}にくくられていなければならないし、各文の最後に;が入ってなければ成らない。

(a, b) => {
a.transform.position = new Vector3( 0,0,0 );
b.transform.position = new Vector3( 1,1,1 );
}

また、以下の様な特徴もある。

http://d.hatena.ne.jp/seraphy/20120609

  • ラムダ式は括弧の外もスコープの対象。
  • スナップショットではなく、生きた参照。

まとめ

というわけで、RemoveAll()のparameterで記述されている件は…

列挙された内容をcというオブジェクトで代用し、MoveNext()が失敗する場合論理値を反転させTrueにし、RemoveAllの対象とする、という意味になる。

以下のサンプルが良い例になるだろうか。

         A a = new A ();
         a.Do ();
         a.Do ();
         a.Do ();
         a.Do ();
         a.Do ();

         public class A
         {
             List<IEnumerator> ien;
             public A ()
             {
                 this.ien = new List<IEnumerator>();
                 this.ien.Add (IenMethod1());
                 this.ien.Add (IenMethod2());
             }
             public void Do()
             {
                 this.ien.RemoveAll( c => !c.MoveNext() );
             }
             IEnumerator IenMethod1()
             {
                 Debug.Log ("befor1");
                 yield return null;
                 Debug.Log ("after1");
             }
             IEnumerator IenMethod2()
             {
                 Debug.Log ("befor2");
                 yield return null;
                 Debug.Log ("after2");
             }
         }

実行結果:

befor1
befor2
after1
after2

あーやっと終わった。スッキリ!

[C#][ObjC]列挙子

Enumerator=調査員。なんだか不穏な感じ。納税状態とかチェックされちゃいそう。
ちゃんと調べてみます。

C#だと

列挙子はGetEnumeratorメソッドを持っていればforeachで使うコレクションにできるIEnumeratorを取得できる。
このメソッドを持ってる=IEnumerableってこと。

IEnumeratorを実装しないとforeach文で列挙できない。
というか、IEnumeratorはforeachの為にある。かのようにMSDNには記述されている。

IEnumerable.GetEnumerator

http://msdn.microsoft.com/ja-jp/library/system.collections.ienumerable.getenumerator(v=vs.80).aspx

IEnumeratorの最初の位置、Reset直後はundefinedが入ってる。というかC#だと何も入ってない?
いずれにせよ最初に動作させるにはMoveNext()を一発かませとな。
コレクションの要素が変更追加削除されると無効になり、これは回復不能。
コレクションの全ての処理が終わるまでロックすることが推奨される。

以上、MSDNより。

ロックってどうやんの?

Unityだと

内容は以下のリンクのp55。
http://www.slideshare.net/lucifuges/unityc
つまり、MoveNextメソッド内の処理に、yield が挟まる間隔単位でcaseが設けられたswitch構文入りの処理をメンバに持つクラスが生成されるとのこと。
newされる度にクラス変数がカウントアップし、返す内容がシフトする仕組み。

Objective-Cだと

http://www.atmarkit.co.jp/fcoding/articles/objc/05/objc05d.html

NSEnumeratorクラス。

NSArrayやNSDictionaryクラス(これを継承したNSMutable**も?)列挙子を内包しているので、for-in使える。

Objective-Cでの使い方

.MoveNextにあたるのが nextObject。
取得する要素が無いとnilを返す。

for( id obj in array )
{
     NSLog( @"value : %@" , obj );
}
for (id key in dic)
{
     NSLog( @"key : %@ nvalue : %@n", key , [dic objectForKey:key] );
}

列挙子の取得から列挙。

NSEnumerator *en = [dic objectEnumerator];
for ( id obj in en)
{
     NSLog( @"value : %@n ", obj );
}

これで中身をズラズラっと取得。

NSDictionaryはkeyの列挙できるkeyEnumeratorがある。

NSEnumerator *en = [dic keyEnumerator];
id key;
while (key = [en nextObject]) {
     NSLog(@"key: %@, value: %@n", key, [dic objectForKey:key]);
}

サンプル

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
    NSLog(@"ApplicationStart");
    
    NSLog(@"NSArray");
    NSArray *arr = [NSArray arrayWithObjects:@"arr0",@"arr1",@"arr2",@"arr3",nil];
    for(id obj in arr)
    {
        NSLog(@"value:%@",obj);
    }
    
    NSLog(@"NSDictionary");
    NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:
                         @"value1",@"key1",
                         @"value2",@"key2", nil];
    for(id key in dic)
    {
        NSLog(@"key:%@, value:%@",key,[dic objectForKey:key]);
    }
    
    NSEnumerator *en = [dic keyEnumerator];
    id key;
    while(key = [en nextObject])
    {
        NSLog(@"en::key:%@, valu:%@",key,[dic objectForKey:key]);
    }
}

[php]だれかのAmazon欲しい物リストを一括して自分のアフィリンク一覧にするサンプル

<?php
//read url
$url = /*欲しい物リストのURL*/;
$afiID = /*自分のAmazonアフィID*/;
$fp = fopen($url, 'r');
$html = "";
while(! feof($fp))
{
	$html = $html.fread($fp,1024) or die("READ");
}
$exps = array();
preg_match_all('//', $html, $exps);
//print_r($exps[0]);
$i = 0;
$j = 1;//list count
$str = 'UTF8&tag='.$afiID.'&';
foreach($exps[0] as $link)
{
	$nlink = preg_replace('/UTF8&/',$str, $link);
	if($i%2 == 0){
		echo $nlink."Package:".$j.'
'; $j++; } $i++; } fclose($fp)or die("CLOSE"); ?>

解説

ページ内のリンクを総ざらい。
ピックアップした中でも商品名がURLに混じってるものだけ拾う。
URLのUTF8と記述されてるあたりにでも自分のアフィIDをtagとしてぶち込む。
欲しい物リスト中には同じリンクが2つずつあるので、一覧を生成する際は偶数のみを使用。