顯示具有 程式語言 標籤的文章。 顯示所有文章
顯示具有 程式語言 標籤的文章。 顯示所有文章

2014年6月16日 星期一

Block in Swift

第一次學習 Block 就上手中教了在 Objective-C 的 Block 作法,
不過在 Swift 裡的作法又變了一個,所以才做了這個教學,
其實 Swift 的 Block 不叫做 Block,叫做 Closures,
它是一個將 Method 當做一個變數使用的應用。

一般的宣告方法如下
var aClosures: (NSString) -> Void = {string in
	NSLog("String: %@", string)
}

Closures 比較特別的是基本宣告都是宣告傳入或傳出的變數型態,
型態所對應變數名稱是在實作的時候才給予,這在基本宣告的時候還可以,
不過下面這個宣告方法就有可能看不懂了。

將 Closures 定義成一個型態之後再宣告
typealias bClosures = (NSNumber!) -> Void

var _bClosures:bClosures = {number in
	 NSLog("Number: %@", number)
;}

這時候如果不看這個型態內部定義的變數的話,就會完全不懂 number 這個變數是啥型態了,
這只能說 Swift 的風格特殊了。

接下來,有宣告當然就要有實作 Closures 的 Method,
其實實作 Method 的方法與 Block 的實作 Method 差異比較小,也可以說作法幾乎是相同的。

func methodWithaClosures(aClosures:(NSString) -> Void)
{
	NSLog("String: %@", string)
}

func methodWithbClosures(closures:bClosures)
{
	closures(NSNumber.numberWithInteger(150))
}

有實作了 Method,這時候就要回到上面將宣告好的 Closures 傳進去了。

var aClosures: (NSString) -> Void = {string in
	NSLog("String: %@", string)
}

typealias bClosures = (NSNumber!) -> Void

var _bClosures:bClosures = {number in
	 NSLog("Number: %@", number)
;}

self.methodWithaClosures(aClosures)

self.methodWithbClosures(_bClosures)

教學就到這邊,下次再看看有哪個東西需要教的了。

2013年8月24日 星期六

Array 的列舉

在早期 C 語言 Array 的列舉有兩種方法,分別為 for 與 for-in 兩種,
到了 Objective-C 這兩種方法也是繼續存在,不過除此之外多了另一個新的方法,
是採用 block 的 enumerate 的方式,它的好處是它會使用另一個 Thread 去處理,
不會影響原本的 Thread 導致畫面凍結的問題,至於這三個要怎麼使用就由我來做教學。

首先假設有一個 Array 名稱為 sampleArray,它的 Code 如下:
	NSArray *sampleArray = [NSArray arrayWithObjects:@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"0", nil];

首先是最簡單的 for 列舉的方式,另外故意在列舉到 8 的時候停止,
至於為什麼,我就慢點再解答了。
	NSLog(@"For 的結果:");
	for (int i = 0; i <= sampleArray.count - 1; i++) {
		NSString *symbol = (NSString *)sampleArray[i];
		NSLog(@"%@", symbol);
	
		if ([symbol isEqualToString:@"8"]) {
			break;
		}
	}
結果如下:








接下來就是 for-in 的列舉,同樣列舉到 8 的時候停止。
	NSLog(@"For in 的結果:");
	for (NSString *symbol in sampleArray) {
		NSLog(@"%@", symbol);
	
		if ([symbol isEqualToString:@"8"]) {
			break;
		}
	}
結果如下:








最後是上面所說的 enumerate 的方式,同樣列舉到 8 的時候停止,
這時停止列舉的方式就與之前的完全不一樣了,這是因為在 block 中無法使用 break; ,所以折衷方案就變成這樣子了。
另外預設的 block 回傳內容如右:^(id obj, NSUInteger idx, BOOL *stop),
其中的 id obj 可以改為對應的 Array 內容,如果你的 Array 內容不固定的話,那還是使用預設的內容。
	NSLog(@"Enumerate 的結果:");
	[sampleArray enumerateObjectsUsingBlock:^(NSString *symbol, NSUInteger idx, BOOL *stop) {
		NSLog(@"%@", symbol);
	
		if ([symbol isEqualToString:@"8"]) {
			*stop = YES;
		}
	}];
結果如下:








另外 enumerate 的列舉有另一個方法,就是反向列舉,使用方法如下:
	NSLog(@"Enumerate Reverse 的結果:");
	[sampleArray enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(NSString *symbol, NSUInteger idx, BOOL *stop) {
		NSLog(@"%@", symbol);
	
		if ([symbol isEqualToString:@"8"]) {
			*stop = YES;
		}
	}];
這時候的結果如下:




基本上 enumerate 的列舉的效能比起另外兩個好上很多,
主要是它是使用另外一個 Theard 來處理的,不過成也 Theard,敗也 Theard,
要是你在列舉的過程中需要使用非同步的處理的話,就 enumerate 的列舉會讓你進入一陣混亂,
因為非同步的處理也是使用另一個 Theard 來處理的,因此會導致在另一個 Theard 中又進入了另一個 Theard,
這會讓這個程式超出你的掌控,所以這時候必須改回原始的 for 或是 for-in 來列舉。


最後,這次的教學到此為止,大家下次再見了。

2013年8月20日 星期二

隱藏 UITableViewCell 的 Edit Control

此教學在 iOS 7 上已經無效了,請改看隱藏 UITableViewCell 的 Edit Control [For iOS 7]


在 UITableViewCell 有一個欄位叫做 Edit Control,這是根據官方的文件所得知的,
不過常常會有需要自定一個當多選 Cell 的時候的圖片,如下圖:


不過 Edit Control 卻是私有的 Code,你無法自定它,
既然不能自定原始的 Edit Control,那就將它藏起來,並做一個新的給覆蓋過去就好了,
那麼要怎麼做了?這篇教學正是教你怎麼做到這件事。

首先就是建立一個繼承 UITableViewCell 的 Class,接下來是讓它與 UITableView 做連動,
要如何做連動我就不教了,這不是本篇的重點,
再來就是在這個 Class 動點手腳了,動手腳的就是 - layoutSubviews 這個 Method,

先 log 現在 cell 裡的 subviews 的資訊
- (void)layoutSubviews
{
	[super layoutSubviews];
	
	if (self.editing) {
		NSLog(@"%@", self.subviews);
	}
	
}

這時候得到的資訊如下圖:

其中 UITableViewCellEditControl 正是 Edit Control 的 Class 名稱,
不過 UITableViewCellEditControl 是私有的 Class,所以無法使用 isKindOfClass: 做判斷,
所以改用另一個繞路的方式來判斷,就是 NSStringFromClass() 將 Class 名稱轉成 NSString 之後再使用 isEqualToString: 去判斷,
這時候再把 Code 寫成下面的樣式:

- (void)layoutSubviews
{
	[super layoutSubviews];
	
	if (!self.editing) {
		return;
	}
	
	void (^enumBlock) (id, NSUInteger, BOOL *) = ^(UIView *subview, NSUInteger idx, BOOL *stop) {
		if ([NSStringFromClass([subview class]) isEqualToString:@"UITableViewCellEditControl"]) {
			[subview setHidden:YES];
	    
			*stop = YES;
		}
	};
	
	[self.subviews enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:enumBlock];
}

這時候礙眼的 Edit Control 就從這樣子:

變成了這樣子了:

這時候就能隨你去增加圖片來取代原始的 Edit Control 了。
本篇教學就到這邊告一個段落,下一次會是" Array 的列舉方法" 的教學,敬請期待。

2013年7月28日 星期日

第一次繪製漸層圖片就上手

這次是使用 UIBezierPath 製作圖片的進階應用繪製一個有漸層效果的圖片,
廢話不多說,趕快下面的教學吧。

// 這次就直接在 viewDidLoad 下面直接繪製
- (void)viewDidLoad
{
	[super viewDidLoad];
	
	// 建立要繪製圖片的座標
	CGRect frame = CGRectMake(20.0f, 20.0f, 200.0f, 200.0f);
	// 將座標中的尺寸取出以便之後使用
	CGSize imageSize = frame.size;
	// 設定邊線的寬度
	CGFloat linWidth = 3.0f;

	// 建立一個畫布,大小為剛剛取出的尺寸
	UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0);

	// 建立一個 RGB 的顏色空間
	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
	// 建立繪製圖片用的 context
	CGContextRef context = UIGraphicsGetCurrentContext();

	// 建立漸層用的顏色,這邊只用兩個顏色,要更多顏色可以自行加入
	UIColor *beginColor = [UIColor colorWithRed:51.0f/255.0f green:102.0f/255.0f blue:204.0f/255.0f alpha:1];
	UIColor *endColor = [UIColor colorWithRed:0 green:0 blue:102.0f/255.0f alpha:1];

	// 將顏色加入陣列中
	NSArray *gradientColors = [NSArray arrayWithObjects:(id)beginColor.CGColor, (id)endColor.CGColor, nil];

	// 建立漸層顏色的啟始點,因為有兩個顏色,所以有兩個數值,如果有多個顏色就需要多個數值
	// 數值的範圍為 0~1。
	CGFloat gradientLocation[] = {0, 1};

	// 建立繪製漸層的基本資訊
	CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (CFArrayRef)gradientColors, gradientLocation);

	// 繪製一個矩型路徑,讓漸層的顏色能畫上去
	UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, imageSize.width, imageSize.height)];
	CGContextSaveGState(context);
	[bezierPath addClip];

	// 建立繪製漸層的起點
	CGPoint beginPoint = CGPointMake(imageSize.width / 2, 0);
	// 建立繪製漸層的終點
	CGPoint endPoint = CGPointMake(imageSize.width / 2, imageSize.height);

	// 將繪製的座標加入要繪製的漸層中
	CGContextDrawLinearGradient(context, gradient, beginPoint, endPoint, 0);
	// 建立圖片邊線的資訊
	CGContextSetStrokeColorWithColor(context, [[UIColor blackColor] CGColor]);
    
	// 將邊線繪製到路徑中
	[bezierPath setLineWidth:linWidth];
	// 將漸層色填滿路徑
	[bezierPath stroke];

	CGContextRestoreGState(context);

	// 將繪製完成的 context 輸出成 UIImage 格式
	UIImage *drawnImage = UIGraphicsGetImageFromCurrentImageContext();

	// 結束 context,並且釋放記憶體
	UIGraphicsEndImageContext();
	CGColorSpaceRelease(colorSpace);
	CGGradientRelease(gradient);

	// 將繪製完成的圖片加到 UIImageView 讓它顯示
	UIImageView *imageView = [[UIImageView alloc] initWithImage:drawnImage];
	[imageView setFrame:frame];

	[self.view addSubview:imageView];
	[imageView release];
}

完成結果如下:

2013年4月16日 星期二

解決經常使用相同的圖片所造成記憶體使用量增加的問題

這次是一個 Category 的進階應用
在某些時候會需要經常重複使用同一張圖片
有可能會造成記憶體使用量的增加,造成不必要的記憶體消耗
這時候可以使用以下方法

先建立一個基於 UIImage 的 Catagory
在 h 檔中建立以下 Code
+ (id)aImage

之後在 m 檔建立以下 Code
其中 aImage 是可以由你自行決定名稱
static UIImage aImage = nil;

+ (id)aImage
{
	if (aImage == nil) {
		aImage = [[UIImage imageNamed:@"__imageName__"] retain];
	}
	
	return aImage;
}

這時候在需要使用這張圖的時候可以直接使用 [UIImage aImage]; 就可以調用這張圖片
而且用過後會一直保留在記憶體中,直到這個程式被終結掉為止,
這樣子就不用一直將相同的圖片重新載入記憶體而造成記憶體的消耗。

2012年6月9日 星期六

Objective-J

在我的朋友FB中看到這個神奇的程式語言
它算是 Objective-J 與 Java 的混合版
不過它是寫網頁的程式不是電腦上的
這倒是很神奇就是了 XDD

它的官方網站在這裡:http://cappuccino.org/
有興趣的人可以去看看