I'm a newbie with integrating ads too, but I was successful in integrating adwhirl after a while. The instructions for section 6 aren't clear at all. This is what you need to do:
1) Inside your ViewController.h:
#import "AdWhirlView.h"
#import "AdWhirlDelegateProtocol.h"
2)
@interface ViewController : UIViewController <AdWhirlDelegate>{
//your code
3) Inside your ViewController.m:
above the @implementation:
#define kSampleAppKey @"yourAdWhirlKey"
4) Inside the @implementation:
#pragma mark AdWhirlDelegate methods
- (NSString *)adWhirlApplicationKey{
return kSampleAppKey;
}
- (UIViewController *)viewControllerForPresentingModalView{
return self;
}
Now for section 7:
5) Inside your ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
AdWhirlView *awView = [AdWhirlView requestAdWhirlViewWithDelegate:self];
[self.view addSubview:awView];
// that's it!
2011年3月30日 星期三
2011年3月22日 星期二
10款iOS高效開發必備的Objective-C類庫
因為iOS SDK相對比較底層,所以開發者就得受累多做一些體力活。不過幸運的是,有很多第三方的類庫可以用來簡化很多不必要的工作.經過作者團隊的慎重討論,他們 評選出了10款能夠極大提高iOS開發效率的類庫,根據原文作者的評價來看,基本上有了這10款工具,做iOS開發就真的跟泡Cocoa一樣了。
MBProgressHUD——進展指示符庫
蘋果的應用程序一般都會用一種優雅的,半透明的進度顯示效果,不過這個API是不公開的,因此你要是用了,很可能被清除出AppStore。而 MBProgressHUD提供了一個替代方案,而且在用戶角度上,實現的效果根本看不出和官方程序有什麼差別。同時還提供了其他附加功能,比如虛擬進展 指示符,以及完成提示信息。整合到項目裡也很容易,這裡不細談了。
ASIHttpRequest——HTTP Network庫
iPhone當然也有自己的HTTP Network API,那為什麼要用ASIHttpRequest呢?因為官方的API簡直跟話癆似的,太羅嗦了!ASIHttpRequest庫極大的簡化了網絡通 信,提供更先進的工具,什麼文件上傳工具,重定向處理工具、驗證工具、等等。只要你手頭的東西跟HTTP有關,用這個絕對能讓你感覺道生活有美好!先看一 段代碼就體會到了。
(void) loadAppDevMag
{
NSURL *url = [NSURL URLWithString:@"http://www.appdevmag.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
// Use when fetching text data
NSString *responseString = [request responseString];
}
{
NSURL *url = [NSURL URLWithString:@"http://www.appdevmag.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
// Use when fetching text data
NSString *responseString = [request responseString];
}
JSON Framework——JSON支持
如果你做的應用和網站服務器有交互,那就得用到JSON了。但事實上,iOS平台的原生類庫根本就不支持JSON,這就略犀利了吧?不過JSON框 架滿足了你的所有需求,包括一個解析器將JSON字符串解析成對象;以及一個生成器從對象生成字符串。這個庫根本就是太流行了,JSON提過很多次了,具 體特點就不多講了,所謂「一段代碼勝千言」,下面用一段代碼演示一下吧。
// JSON string -> NSDictionary
NSString *jsonString = @"{\"foo\": \"bar\"}";
NSDictionary *dictionary = [jsonString JSONValue];
NSLog(@"Dictionary value for \"foo\" is \"%@\"", [dictionary objectForKey:@"foo"]);
// NSDictionary -> JSON string
NSString *newJsonString = [dictionary JSONRepresentation];
NSString *jsonString = @"{\"foo\": \"bar\"}";
NSDictionary *dictionary = [jsonString JSONValue];
NSLog(@"Dictionary value for \"foo\" is \"%@\"", [dictionary objectForKey:@"foo"]);
// NSDictionary -> JSON string
NSString *newJsonString = [dictionary JSONRepresentation];
Flurry——詳盡的使用統計
通過Furry你可以得到應用的用戶人數,用戶活躍度,用戶來源等統計信息。但是他最厲害的地方是,你可以追蹤應用本身的事件和錯誤記錄,所有這些 數據都會在一個類似Google Analytics的界面上顯示,這樣就很容易掌握用戶的行為和出現的問題。當然,這個星球上很多統計工具,但是這款是作者個人比較推崇的解決方案。
RegexKitLite——正則表達式支持
正則表達式大家都知道。但是iPhone SDK居然當他不存在?這怎麼能忍啊!果斷用RegexKitLite。雖然叫的是Lite,但是功能很full。示例代碼。
// finds phone number in format nnn-nnn-nnnn
NSString *regEx = @"[0-9]{3}-[0-9]{3}-[0-9]{4}";
for(NSString *match in [textView.text componentsMatchedByRegex:regEx]) {
NSLog(@"Phone number is %@", match);
}
NSString *regEx = @"[0-9]{3}-[0-9]{3}-[0-9]{4}";
for(NSString *match in [textView.text componentsMatchedByRegex:regEx]) {
NSLog(@"Phone number is %@", match);
}
Facebook iOS SDK——Facebook API類庫
大體來講就是iPhone上的Facebook login,完全支持Facebook Graph API和the older REST api。如果你的應用跟Facebook有關,相信我,用這個吧。
SDWebImage——簡化網絡圖片處理
用SDWebImage調用網站上的圖片,跟本地調用內置在應用包裡的圖片一樣簡單。操作也很簡單,舉例說明
[imageView setImageWithURL:[NSURL URLWithString:@"http://examp
類似的功能在Three20裡也有,這個過會兒再說。相比而言,SDWebImage主要是提供一個小而精的簡捷方便的解決方案
GData client——iPhone上所有Google相關服務的類庫
名字就說明一切了。跟Google相關的,值得一提的是,這個項目很開放。有很多示例程序供下載。
CorePlot——2D圖形繪圖儀
CorePlot有很多解決方案將你的數據可視。,同時也會提供各種迷人的圖形效果,比如棒狀圖、餅狀圖、線狀圖等等,在他們網站上也提供了大量的范例圖形,很多股票價格應用,游戲分數,個人財務管理都在用。
Three20——通用iOS庫
Three20類庫是Facebook自己做的,大而全是他最大的特色。把他整合到已有的項目中可能得費點周折,不過如果一開始你就用上了Three20,尤其是牽扯到很多web相關的項目的時候,你就能深刻體會到神馬叫給力了。
2011年2月25日 星期五
2011年2月20日 星期日
NSURLConnection
在預設的情況下,一個 iPhone App 只有一條執行緒(Thread),簡單的說就是同一時間只能做一件事,所以當你用 NSData 或 NSString 的 initWithContentsOfURL 的方法來載入網頁資料時,整個程式就會停在那裡,直到網頁資料都下載完了後,才會繼續執行下一行的程式碼。繼然程式停在那不動,當然你不論怎麼加上其它的動畫或View都不會有作用,這就是我昨天一直失敗的原因。
所以有兩種方式來解決這個問題,一是自己開 Thread 來用時做好幾件事,二是使用委託處理的方式,把要做的事情委託出去,等事情做完後,被委託的人會通知你事情已經處理完了。這也就是 iOS 一直強調的 delgate model。
自己開 Thread 並不適合用在 iT邦幫忙 App 裡,因為我必需要知道網頁資料何時會下載完畢,等下載完畢後,再把載入等待畫面給移除。所以我需要找到一個能幫我下載網頁資料,然後下載完後能通知我的一個類別,那個就是 - NSURLConnection。
NSURLConnection 宣告使用的程式碼如下:
它需要兩個參數,一個是 NSURLRequest 物件,另一個是 delegate 物件。上面的程式碼把 delegate 指向自己(self),也就是目前所在的類別來接受 NSURLConnect 的事件。最重要的有四個事件處理的方法:
htmlData 是個 NSMutableData 的物件,當 NSURLConnect 連上網站時,我先把 htmlData 清空準備來接收網頁資料。NSURLConnection 會把網頁資料一段一段下載回來,每當下載一部份時,didReceiveData 方法會收到通知,這時我把資頁資料給存放進 htmlData 物件裡。等到全部下載回來後,會呼叫 connectionDidFinishLoading 方法,這時我就把網頁的資料給印出來...
當下載的過程中發生錯誤時,會呼叫 didFailWithError 的方法,這時我會印出錯誤訊息,看看發生了什麼事。
所以有兩種方式來解決這個問題,一是自己開 Thread 來用時做好幾件事,二是使用委託處理的方式,把要做的事情委託出去,等事情做完後,被委託的人會通知你事情已經處理完了。這也就是 iOS 一直強調的 delgate model。
自己開 Thread 並不適合用在 iT邦幫忙 App 裡,因為我必需要知道網頁資料何時會下載完畢,等下載完畢後,再把載入等待畫面給移除。所以我需要找到一個能幫我下載網頁資料,然後下載完後能通知我的一個類別,那個就是 - NSURLConnection。
NSURLConnection 宣告使用的程式碼如下:
- NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://ithelp.ithome.com.tw/?tab=share"]];
- [NSURLConnection connectionWithRequest:request delegate:self];
它需要兩個參數,一個是 NSURLRequest 物件,另一個是 delegate 物件。上面的程式碼把 delegate 指向自己(self),也就是目前所在的類別來接受 NSURLConnect 的事件。最重要的有四個事件處理的方法:
- //是否收到網站的回應
- - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
- [htmlData setLength:0];
- }
- //收到網站傳回的資料
- - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
- [htmlData appendData:data];
- }
- //網頁資料下載完畢
- - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
- NSLog(@"Succeeded! Received %d bytes of data",[htmlData length]);
- NSLog(@"%@", [[NSString alloc] initWithData:htmlData encoding:NSUTF8StringEncoding]);
- }
- //網路連線錯誤
- - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
- [connection release];
- NSLog(@"Connection failed! Error - %@ %@",
- [error localizedDescription],
- [[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
- }
htmlData 是個 NSMutableData 的物件,當 NSURLConnect 連上網站時,我先把 htmlData 清空準備來接收網頁資料。NSURLConnection 會把網頁資料一段一段下載回來,每當下載一部份時,didReceiveData 方法會收到通知,這時我把資頁資料給存放進 htmlData 物件裡。等到全部下載回來後,會呼叫 connectionDidFinishLoading 方法,這時我就把網頁的資料給印出來...
當下載的過程中發生錯誤時,會呼叫 didFailWithError 的方法,這時我會印出錯誤訊息,看看發生了什麼事。
2011年2月15日 星期二
iPhone/Mac Objective-C 記憶體管理教程和原理剖析
版權聲明
此文版權歸作者Vince Yuan (vince.yuan#gmail.com)所有。歡迎非營利性轉載,轉載時必須包含原始鏈接http://vinceyuan.cnblogs.com/,且必須包含此版權聲明的完整內容。
版本 1.1 發表於2010-03-08
前言
初學objectice-C的朋友都有一個困惑,總覺得對objective-C的內存管理機制琢磨不透,程序經常內存洩漏或莫名其妙的崩潰。我在這裡總結了自己對objective-C內存管理機制的研究成果和經驗,寫了這麼一個由淺入深的教程。希望對大家有所幫助,也歡迎大家一起探討。
此文涉及的內存管理是針對於繼承於NSObject的Class。
一 基本原理
Objective-C的內存管理機制與.Net/Java那種全自動的垃圾回收機制是不同的,它本質上還是C語言中的手動管理方式,只不過稍微加了一些自動方法。
1 Objective-C的對象生成於堆之上,生成之後,需要一個指針來指向它。
ClassA *obj1 = [[ClassA alloc] init];
2 Objective-C的對象在使用完成之後不會自動銷毀,需要執行dealloc來釋放空間(銷毀),否則內存洩露。
[obj1 dealloc];
這帶來了一個問題。下面代碼中obj2是否需要調用dealloc?
ClassA *obj1 = [[ClassA alloc] init];
ClassA *obj2 = obj1;
[obj1 hello]; //輸出hello
[obj1 dealloc];
[obj2 hello]; //能夠執行這一行和下一行嗎?
[obj2 dealloc];
不能,因為obj1和obj2只是指針,它們指向同一個對象,[obj1 dealloc]已經銷毀這個對象了,不能再調用[obj2 hello]和[obj2 dealloc]。obj2實際上是個無效指針。
如何避免無效指針?請看下一條。
3 Objective-C采用了引用計數(ref count或者retain count)。對象的內部保存一個數字,表示被引用的次數。例如,某個對象被兩個指針所指向(引用)那麼它的retain count為2。需要銷毀對象的時候,不直接調用dealloc,而是調用release。release會讓retain count減1,只有retain count等於0,系統才會調用dealloc真正銷毀這個對象。
ClassA *obj1 = [[ClassA alloc] init]; //對象生成時,retain count = 1
[obj1 release]; //release使retain count減1,retain count = 0,dealloc自動被調用,對象被銷毀
我們回頭看看剛剛那個無效指針的問題,把dealloc改成release解決了嗎?
ClassA *obj1 = [[ClassA alloc] init]; //retain count = 1
ClassA *obj2 = obj1; //retain count = 1
[obj1 hello]; //輸出hello
[obj1 release]; //retain count = 0,對象被銷毀
[obj2 hello];
[obj2 release];
[obj1 release]之後,obj2依然是個無效指針。問題依然沒有解決。解決方法見下一條。
4 Objective-C指針賦值時,retain count不會自動增加,需要手動retain。
ClassA *obj1 = [[ClassA alloc] init]; //retain count = 1
ClassA *obj2 = obj1; //retain count = 1
[obj2 retain]; //retain count = 2
[obj1 hello]; //輸出hello
[obj1 release]; //retain count = 2 – 1 = 1
[obj2 hello]; //輸出hello
[obj2 release]; //retain count = 0,對象被銷毀
問題解決!注意,如果沒有調用[obj2 release],這個對象的retain count始終為1,不會被銷毀,內存洩露。(1-4可以參考附件中的示例程序memman-no-pool.m)
這樣的確不會內存洩露,但似乎有點麻煩,有沒有簡單點的方法?見下一條。
5 Objective-C中引入了autorelease pool(自動釋放對象池),在遵守一些規則的情況下,可以自動釋放對象。(autorelease pool依然不是.Net/Java那種全自動的垃圾回收機制)
5.1 新生成的對象,只要調用autorelease就行了,無需再調用release!
ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1 但無需調用release
5.2 對於存在指針賦值的情況,代碼與前面類似。
ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1
ClassA *obj2 = obj1; //retain count = 1
[obj2 retain]; //retain count = 2
[obj1 hello]; //輸出hello
//對於obj1,無需調用(實際上不能調用)release
[obj2 hello]; //輸出hello
[obj2 release]; //retain count = 2-1 = 1
細心的讀者肯定能發現這個對象沒有被銷毀,何時銷毀呢?誰去銷毀它?(可以參考附件中的示例程序memman-with-pool.m)請看下一條。
6 autorelease pool原理剖析。(其實很簡單的,一定要堅持看下去,否則還是不能理解Objective-C的內存管理機制。)
6.1 autorelease pool不是天生的,需要手動創立。只不過在新建一個iphone項目時,xcode會自動幫你寫好。autorelease pool的真名是NSAutoreleasePool。
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6.2 NSAutoreleasePool內部包含一個數組(NSMutableArray),用來保存聲明為autorelease的所有對象。如果一個對象聲明為autorelease,系統所做的工作就是把這個對象加入到這個數組中去。
ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1,把此對象加入autorelease pool中
6.3 NSAutoreleasePool自身在銷毀的時候,會遍歷一遍這個數組,release數組中的每個成員。如果此時數組中成員的retain count為1,那麼release之後,retain count為0,對象正式被銷毀。如果此時數組中成員的retain count大於1,那麼release之後,retain count大於0,此對象依然沒有被銷毀,內存洩露。
6.4 默認只有一個autorelease pool,通常類似於下面這個例子。
int main (int argc, const char *argv[])
{
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
// do something
[pool release];
return (0);
} // main
所有標記為autorelease的對象都只有在這個pool銷毀時才被銷毀。如果你有大量的對象標記為autorelease,這顯然不能很好的利用內存,在iphone這種內存受限的程序中是很容易造成內存不足的。例如:
int main (int argc, const char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int i, j;
for (i = 0; i < 100; i++ )
{
for (j = 0; j < 100000; j++ )
[NSString stringWithFormat:@"1234567890"];//產生的對象是autorelease的。
}
[pool release];
return (0);
} // main
(可以參考附件中的示例程序memman-many-objs-one-pool.m,運行時通過監控工具可以發現使用的內存在急劇增加,直到pool銷毀時才被釋放)你需要考慮下一條。
7 Objective-C程序中可以嵌套創建多個autorelease pool。在需要大量創建局部變量的時候,可以創建內嵌的autorelease pool來及時釋放內存。(感謝網友hhyytt和neogui的提醒,某些情況下,系統會自動創建autorelease pool, 請參見第四章)
int main (int argc, const char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int i, j;
for (i = 0; i < 100; i++ )
{
NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
for (j = 0; j < 100000; j++ )
[NSString stringWithFormat:@"1234567890"];//產生的對象是autorelease的。
[loopPool release];
}
[pool release];
return (0);
} // main
(可以參考附件中的示例程序memman-many-objs-many-pools.m,佔用內存的變化極小)
訂閱:
文章 (Atom)