objective-c java_程序员转型指南 当Java遇见了Objective-C
【51CTO譯文】目前在移動開發(fā)領(lǐng)域最重要的兩個平臺分別為Android平臺和iOS,在兩個平臺開發(fā)應(yīng)用分別要用Java和Objective-C語言。雖然Java和Objective-C就像是處在兩個不同的世界,但這兩種編程語言以及它們的平臺庫等等還是有許多相似的地方。本文為51CTO獨家譯文,講述了外國開發(fā)者Genadiy Shteyman從Java開發(fā)轉(zhuǎn)向Objective-C需要掌握技能。
以下為全部譯文,(文章中的“我”指代"Genadiy Shteyman"):
最近一段時間,我從編寫企業(yè)Java應(yīng)用轉(zhuǎn)向使用Objective-C。經(jīng)過長時間的困擾之后,我發(fā)現(xiàn)兩者的相似之處很多,如果能夠早些讀到相關(guān)的文章,轉(zhuǎn)換工作會容易得多。
所以我寫下這篇文章,想要幫助Java程序員快速的掌握Objective-C開發(fā)的主要特點。我使用一個社交網(wǎng)絡(luò)應(yīng)用作為例子,演示怎樣用這兩種語言建立開發(fā)環(huán)境。例子中會包括創(chuàng)建基本對象與比較兩種語言的MVC設(shè)計模式,還會演示兩種語言中數(shù)據(jù)的存儲和獲取。
Objective-C開發(fā):從哪里開始
開發(fā)iPhone應(yīng)用,首先最好要使用Mac電腦。最新的Mac OS X 10.6版本通常包含了一份Xcode IDE,以及使用Objective-C的配套iPhone開發(fā)軟件工具套裝(圖表一)。
圖表一:Xcode IDE開發(fā)環(huán)境,項目視圖
2010年11月,蘋果發(fā)布了期待已久的iOS SDK 4.2,其中包含了豐富的框架和功能,用來搭建互動iPhone應(yīng)用。Xcode還包含了一個仿真器,可以讓你在電腦中模擬程序運行在手機上的效果。
Objective-C是iPhone應(yīng)用的主要開發(fā)語言。對Java開發(fā)者來說,幸運的是Objective-C是完全面向?qū)ο蟮?#xff0c;使用和其他OO語言相同的理念——繼承、多態(tài)和封裝等等。定義一個類(Objective-C中稱為module或.m文件),首先要定義一個接口(一個header或.h文件),然后把它引入到類中。
我們來看這個社交網(wǎng)絡(luò)應(yīng)用的例子,這個應(yīng)用需要建立一個聯(lián)系冊,讓你和朋友們時常保持聯(lián)系。朋友的檔案存儲在FriendProfile對象中,包含四個字段:朋友的名字、城市、國家和電話號碼,如Listing One所示:
Listing?One
//??FriendProfile.h
#import?
#import?
@interface?FriendProfile?:?NSObject?{
}
@property?(nonatomic,?retain)?NSString?*?name;
@property?(nonatomic,?retain)?NSString?*?country;
@property?(nonatomic,?retain)?NSString?*?city;
@property?(nonatomic,?retain)?NSString?*?phoneNbr;
@end
//FriendProfile.m
#import?"FriendProfile.h"
@implementation?FriendProfile
@synthesize?name;
@synthesize?country;
@synthesize?city;
@synthesize?phoneNbr;
@end
在這個例子中,接口FriendProfile:NSObject表示我們定義了一個叫做FriendProfile的接口,它從NSObject基類中繼承各種功能。NSObject是Objective-C的根類,大多數(shù)Objective-C中用到的類都會從中繼承,這和Java中的Object類相似。接下來,我們分配多個NSString類型變量(等同于Java中的String類型)用來存儲朋友的數(shù)據(jù)。然后是建立FriendProfile類,使用@synthesize關(guān)鍵字自動創(chuàng)建各種get和set方法。建立一個FriendProfile對象可以使用如下的語句:
FriendProfile?*?profile?=?[[FriendProfile?alloc]?init];
這里的alloc和init就像Java里的new關(guān)鍵字,用來在內(nèi)存中建立FriendProfile對象。接下來,就可以給對象的各種字段賦值了。
[profile?setName:@"Albert"];
[profile?setCountry:@"USA"];
[profile?setCity:@"Houston"];
[profile?setPhoneNbr:@"123-456-789"];
或者可以更簡單一點:
profile.name?=?@"Albert";
profile.country?=?@"USA";
profile.city?=?@"Houston;
profile.phoneNbr?=?@"123-456-789";
想要充分了解Objective-C的語法和功能可以去蘋果的開發(fā)者站點,那里的語言參考編寫的非常好。
Java的構(gòu)造
在Java中,如果我們想寫一個FriendProfile類,所做的和Objective-C會非常相像,就像Listing Two所示:
Listing?Two
packagecom.vo;
publicclassFriendProfile?{
privateString?name;
privateString?country;
privateString?city;
privateString?phoneNbr;
publicString?getName()?{
returnname;
}
publicvoidsetName(String?name)?{
this.name?=?name;
}
publicString?getCountry()?{
returncountry;
}
publicvoidsetCountry(String?country)?{
this.country?=?country;
}
publicString?getCity()?{
returncity;
}
publicvoidsetCity(String?city)?{
this.city?=?city;
}
publicString?getPhoneNbr()?{
returnphoneNbr;
}
publicvoidsetPhoneNbr(String?phoneNbr)?{
this.phoneNbr?=?phoneNbr;
}
}
Listing Two中提供了相似的字段,但是那些get和set必須清楚的寫出來?,F(xiàn)在我們看看怎樣在通訊錄里添加一個新朋友,參加Listing Three:
Listing?Three
publicclassFriendlyServletControllerextendsHttpServlet?{
privatestaticfinallongserialVersionUID?=?1L;
/**
*?@see?HttpServlet#doGet(HttpServletRequest?request,
*?HttpServletResponse?response)
*/
protectedvoiddoGet(HttpServletRequest?request,
HttpServletResponse?response)
throwsServletException,?IOException?{
doPost(request,?response);
}
/**
*?@see?HttpServlet#doPost(HttpServletRequest?request,
*?HttpServletResponse?response)
*/
protectedvoiddoPost(HttpServletRequest?request,
HttpServletResponse?response)
throwsServletException,?IOException?{
response.setContentType("text/html");
PrintWriter?out?=?response.getWriter();
finalString?action?=
request.getParameter("requestedAction");
if(action==null||?action.trim().length()==0){
out.println("invalid?action?requested");
return;
}
else
if(action.equalsIgnoreCase("addToContacts")){
String?name?=?request.getParameter("name");
String?country?=?request.getParameter("country");
String?city?=?request.getParameter("city");
String?phoneNbr?=?request.getParameter("phoneNbr");
//normally?you?have?to?validate?browser-originated?requests
booleanvalidParameters?=
validateParameters(name,?country,?city,?phoneNbr);
if(validParameters==false){
out.println(
"please?verify?and?submit?correct?information");
return;
}
FriendProfile?newProfile?=newFriendProfile();
newProfile.setName(name);
newProfile.setCountry(country);
newProfile.setCity(city);
newProfile.setPhoneNbr(phoneNbr);
ProfileManager.getInstance().addToContacts(newProfile);
out.println("Your?friend?is?added?to?contacts");
return;
}
else{
out.println("invalid?action?requested");
return;
}
}
}
在這個例子里,FriendlyServletController類從HTTPServlet中獲取行為,HTTPServlet是Java的客戶端組件類,負(fù)責(zé)處理瀏覽器的請求。當(dāng)用戶登入網(wǎng)站并且決定添加一個朋友時,他會在HTML表單的字段中填入數(shù)據(jù),表單提交時,Servlet收到并驗證請求的參數(shù),并創(chuàng)建一個FriendProfile對象,在內(nèi)存中存儲數(shù)據(jù)。而ProfileManager類會把你的FriendProfile對象存儲到數(shù)據(jù)庫中。
Objective-C的MVC模式
在Java Web應(yīng)用中常采用Model-View-Controller(MVC)設(shè)計模式,iPhone開發(fā)中也是如此。如果你在iOS Reference Library中查找UIViewController類的定義,你會發(fā)現(xiàn)這樣的話:“UIViewController類為iPhone應(yīng)用提供最基本的視圖管理模型……你可以使用UIViewController實例來管理視圖結(jié)構(gòu)?!盪IViewController實際上是一個控制器組件,用來觸發(fā)業(yè)務(wù)邏輯,更新客戶端的視圖。
圖表2:Model-View-Controller(MVC)設(shè)計模式
如果你想在Xcode中創(chuàng)建一個UIViewController類型的對象,可以選擇通過XIB文件來創(chuàng)建。這種特殊的Xcode文件定義了圖形用戶界面或者說視圖,包含了各種不同的控件,比如按鈕、圖表和標(biāo)簽等等。
回到我們的例子中來,假設(shè)你已經(jīng)在聯(lián)系列表中添加了幾個朋友,現(xiàn)在想按下某個朋友的鏈接來看查看他的詳細(xì)信息,這個功能可以通過定義控制器類來完成。代碼請見Listing Four:
Listing?Four
//??FriendProfileViewController.h
#import?
@classFriendProfile;
@classDatabaseController;
@classMFriendProfile;
//?define?our?custom?controller?to?inherit?from
//?the?UIViewController?class
@interface?FriendProfileViewController?:?UIViewController?{
FriendProfile?*?profile;
MFriendProfile?*?mprofile;
DatabaseController?*dbController;
}
@property(nonatomic,?retain)?IBOutlet?UILabel?*lname;
@property(nonatomic,?retain)?IBOutlet?UILabel?*lcountry;
@property(nonatomic,?retain)?IBOutlet?UILabel?*lcity;
@property(nonatomic,?retain)?IBOutlet?UILabel?*lphoneNbr;
-(IBAction)buttonPressed:(id)sender;
@end
#import?"FriendProfileViewController.h"
#import?"FriendProfile.h"
#import?"DatabaseController.h"
#import?"MFriendProfile.h"
@implementation?FriendProfileViewController
...
//?Implement?viewDidLoad?to?do?additional?setup?after
//?loading?the?view,?typically?from?a?nib.
-?(void)viewDidLoad?{
[super?viewDidLoad];
//create?sample?profile
profile?=?[[FriendProfile?alloc]?init];
profile.name?=?@"Albert";
profile.country?=?@"USA";
profile.city?=?@"Houston";
profile.phoneNbr?=?@"123-456-789";
//show?profile?on?a?screen
lname.text?=?profile.name;
lcountry.text?=?profile.country;
lcity.text?=?profile.city;
lphoneNbr.text?=?profile.phoneNbr;
}
//call?the?model?to?bring?friend?information?from?database
-(IBAction)buttonPressed:(id)sender{
NSLog(@"fetching?friend?profile?by?name.");
//?name?is?hardcoded?for?demo?purposes.
//?Usually?entered?by?user.
mprofile?=?(MFriendProfile*)
[dbController?getFriendProfileObjectbyName:@"Albert"];
lname.text?=?mprofile.name;
lcountry.text?=?mprofile.country;
lcity.text?=?mprofile.city;
lphoneNbr.text?=?mprofile.phoneNbr;
}
這段代碼中,我們創(chuàng)建了一個FriendProfileViewController實例,在我們定義的View Bundle中進(jìn)行初始化,顯示出朋友的各種信息。
Alloc和initWithNibName都是控制器類創(chuàng)建實例時使用的方法,和Java的new關(guān)鍵字功能一樣。
模型在裝載視圖時開始啟動。每個控制器都有一些從父類UIViewController繼承而來的生命周期方法。比如ViewdidLoad方法就是其中之一,它負(fù)責(zé)在視圖裝載之后的額外設(shè)置,從數(shù)據(jù)庫中取出信息,更新視圖。在最簡單的情況下,我們的視圖包含一系列標(biāo)簽,或者是UILabel類型的對象,可以在應(yīng)用運行時設(shè)置各種文本,用戶可以立即看見朋友信息被更新了。
Java的MVC模式
下面來看看如何使用Java后臺在瀏覽器窗口中顯示出朋友的詳細(xì)信息。我們稍微修改一下FriendlyServletController即可,代碼請見Listing Five:
Listing?Five
importjava.io.IOException;
importjava.io.PrintWriter;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importcom.model.ProfileManager;
importcom.vo.FriendProfile;
/**
*?Servlet?implementation?class?FriendlyServletController
*/
publicclassFriendlyServletControllerextendsHttpServlet?{
privatestaticfinallongserialVersionUID?=?1L;
/**
*?@see?HttpServlet#doGet(HttpServletRequest?request,
*?HttpServletResponse?response)
*/
protectedvoiddoGet(HttpServletRequest?request,
HttpServletResponse?response)
throwsServletException,?IOException?{
doPost(request,?response);
}
/**
*?@see?HttpServlet#doPost(HttpServletRequest?request,
*??????HttpServletResponse?response)
*/
protectedvoiddoPost(HttpServletRequest?request,
HttpServletResponse?response)
throwsServletException,?IOException?{
response.setContentType("text/html");
PrintWriter?out?=?response.getWriter();
finalString?action?=?request.getParameter("requestedAction");
if(action==null||?action.trim().length()==0){
out.println("invalid?action?requested");
return;
}
elseif(action.equalsIgnoreCase("showFriendProfile")){
String?name?=?request.getParameter("name");
FriendProfile?existProfile?=newFriendProfile();
existProfile.setName(name);
existProfile?=
ProfileManager.getInstance().lookupContact(existProfile);
if(existProfile==null){
out.println("profile?was?not?found");
}else{
out.println("here?is?your?contact?information:"+
existProfile.getName()?+"?from?"+
existProfile.getCity()?+"?in?"+
existProfile.getCountry()?+"?at?"+
existProfile.getPhoneNbr());
}
return;
}
elseif(action.equalsIgnoreCase("addToContacts")){
String?name?=?request.getParameter("name");
String?country?=?request.getParameter("country");
String?city?=?request.getParameter("city");
String?phoneNbr?=?request.getParameter("phoneNbr");
//normally?you?have?to?validate?browser-originated?requests
booleanvalidParameters?=
validateParameters(name,?country,?city,?phoneNbr);
if(validParameters==false){
out.println("please?verify?and?submit?correct?information");
return;
}
FriendProfile?newProfile?=newFriendProfile();
newProfile.setName(name);
newProfile.setCountry(country);
newProfile.setCity(city);
newProfile.setPhoneNbr(phoneNbr);
ProfileManager.getInstance().addToContacts(newProfile);
out.println("Your?friend?is?added?to?contacts");
return;
}
else{
out.println("invalid?action?requested");
return;
}
}
//basic?parameter?validation?routine
privatebooleanvalidateParameters(String?name,?String?country,
String?city,?String?phoneNbr){
/basic?validation?to?checkifall?parameters?are?sent
if(name==null||?name.trim().length()==0||
country==null||?country.trim().length()==0||
city?==null||?city.trim().length()==0||
phoneNbr?==null||?phoneNbr.trim().length()==0){
returnfalse;
}
returntrue;
}
}
在這個例子中,FriendlyServletController接收表單產(chǎn)生的HTTP請求,我們特別編寫了一個事件叫做showFriendProfile。這里我們的模型是一個ProfileManager對象,負(fù)責(zé)通過朋友姓名在數(shù)據(jù)庫中查找記錄。然后查找到的數(shù)據(jù)庫記錄會以FriendProfile對象的形式返回到控制器,其中包含了各種詳細(xì)信息,組成視圖顯示在瀏覽器窗口中。
Objective-C的數(shù)據(jù)庫訪問
較復(fù)雜的應(yīng)用都會用到某類數(shù)據(jù)存儲方式,通常是一個數(shù)據(jù)庫。蘋果推薦開發(fā)者使用稱為Core Data的Cocoa API框架進(jìn)行數(shù)據(jù)庫存取操作。Core Data框架能夠直接與SQLite數(shù)據(jù)庫相結(jié)合(我們例子中的數(shù)據(jù)庫運行在移動設(shè)備上)。Core Data隱藏了復(fù)雜的SQL操作,取而代之的是非常方便的NSManagedObject界面,你可以直接操作整個對象實例的各種字段,這些字段可以自動存入數(shù)據(jù)庫。Core Data框架的另一個方便之處是在數(shù)據(jù)庫中創(chuàng)建表(以及向表中添加關(guān)聯(lián)與限制),這些都可以在Core Data的用戶界面中完成。
圖表3:Core Data stack結(jié)構(gòu)
現(xiàn)在回到我們的社交網(wǎng)絡(luò)應(yīng)用例子,看看怎么從數(shù)據(jù)庫中取出朋友的信息。我們使用SQLite 和Core Data API,但首先我們要稍微修改一下FriendProfile類,代碼請見Listing Six:
Listing?Six
//FriendProfile.h?interface?file//?MFriendProfile.h
#import?
#import?
@interface?MFriendProfile?:?NSManagedObject?{
}
@property?(nonatomic,?retain)?NSString?*name;
@property?(nonatomic,?retain)?NSString?*?country;
@property?(nonatomic,?retain)?NSString?*?city;
@property?(nonatomic,?retain)?NSString?*?phoneNbr;
@end
//?MFriendProfile.m
#import"MFriendProfile.h"
@implementation?MFriendProfile
@dynamicname;
@dynamiccountry;
@dynamiccity;
@dynamicphoneNbr;
@end
這里的FriendProfile類與Listing One中的不同之處在于在這里我加入了Core Data框架的頭文件。而且在這里我們的類是從NSManagedObject中擴展出來,帶有了Core Data對象需要的全部基本行為。Core Data的NSManagedObject類中使用到的Accessor則在應(yīng)用運行時動態(tài)創(chuàng)建。如果你想在FriendProfile類中聲明或使用屬性,但不想在編譯時出現(xiàn)缺少方法的警告,可以使用@dynamic指令,而不是@synthesize指令。
使用NSManagedObject API有些復(fù)雜,但你理解之后就會變得很好用。Listing Seven是一個示例方法,從數(shù)據(jù)庫的FRIENDPROFILE表中取得朋友的信息。表包含四列:NAME、COUNTRY、CITY和PHONE-NBR。
Listing?Seven
//?DatabaseController.m
#import"DatabaseController.h"
#import?
#define?kDatabaseName?@"SocialNetworking.sqlite"
...
-?(NSManagedObject?*)getFriendProfileObjectbyName:(NSString?*)name{
managedObjectContext?=?[self?managedObjectContext];
//createsort?descriptorstospecify?preferred?sortorder
NSSortDescriptor?*sortDescriptor?=
[[NSSortDescriptor?alloc]?initWithKey:@"name"ascending:YES];
NSArray?*sortDescriptors?=
[[NSArray?alloc]??initWithObjects:sortDescriptor,nil];
//specifywhereclause
NSPredicate?*predicate?=
[NSPredicate?predicateWithFormat:@"name?==?%d",name];
//fetchour?friendís?profilefromdatabasetable
NSEntityDescription?*entity?=
[NSEntityDescription?entityForName:@"MFRIENDPROFILE"
inManagedObjectContext:managedObjectContext];
NSFetchRequest?*request?=?[[NSFetchRequest?alloc]?init];
[request?setEntity:entity];
//Setthe?predicateforthecurrentview
if?(predicate)
{
[request?setPredicate:predicate];
}
if?(sortDescriptors)
{
[request?setSortDescriptors:sortDescriptors];
}
NSError?*error?=?nil;
NSMutableArray?*results?=?[[managedObjectContext
executeFetchRequest:request?error:&error]?mutableCopy];
if?(error)
{
NSLog(@"error?in?getFriendProfileObjectbyName:%@",
[error?userInfo]);
}
[sortDescriptor?release];
[sortDescriptors?release];
[predicate?release];
if?([resultscount]?>?0)?{
return[results?objectAtIndex:0];
}
returnnil;
}
getFriendProfileObjectbyName方法把朋友的姓名作為一個參數(shù)接收過來。通過使用Core Data API,我們可以指定在哪一個表中進(jìn)行查詢和排序,并且在后臺執(zhí)行SQL語句。
SQL>select*fromFriendProfilewherename="Albert";
Core Data API有許多種沒有封裝的“半成品”代碼,可以訪問NSManagedObjectContext、NSPersistentStoreCoordinator和NSManaged-ObjectModel對象。你可以復(fù)制這些代碼,只要你取得了FriendProfile對象,就能以下面的形式取得它的屬性:
NSString*name=????????FriendProfile.name;
NSString*?country?=?FriendProfile.country;
NSString*?city?=????????FriendProfile.city;
NSString*?phoneNbr?=????FriendProfile.phoneNbr;
總的來說,Core Data是一個非常有用的功能,可以讓你通過圖表來定義數(shù)據(jù)表和管理,可以動態(tài)生成相應(yīng)的對象,而且無需使用復(fù)雜的SQL語句。但不好的方面是這里有大量的沒有經(jīng)過封裝的代碼,這樣你在使用它們與測試時需要非常小心。
Java:數(shù)據(jù)庫存取
Java有許多數(shù)據(jù)庫框架。在我看來,Hibernate是和Core Data API最相像的Java框架。Hibernate使用的是對象關(guān)系映射(Object-Relational Mapping,ORM)機制,這樣你可以通過簡單的在對象中設(shè)置字段并且直接映射成數(shù)據(jù)庫中的表來把對象數(shù)據(jù)放入關(guān)系型數(shù)據(jù)庫中。映射可以通過XML文件,也可以通過Java 5中的metadata annotation方法獲得。Listing Eight是使用XML進(jìn)行映射的一個例子。
Listing Eight
此例中,Listing Two中的FriendProfile對象被映射到數(shù)據(jù)庫中的一個同名表,這是一種傳統(tǒng)的數(shù)據(jù)映射做法。對象的四個字段被直接映射到表中的四列,通過映射,Hibernate可以使用SQL語句來完成各種操作。
另一個配置文件叫做hibernate.cfg.xml,包含了數(shù)據(jù)庫連接設(shè)置的詳細(xì)信息,包括數(shù)據(jù)庫URL、數(shù)據(jù)庫驅(qū)動以及用戶名和密碼等,代碼請見Listing Nine:
Listing?Eight
Listing Nine中我們導(dǎo)入了所有需要的Hibernate庫,創(chuàng)建了一個Hibernate Session并且開始事務(wù),接下來我們僅簡單使用了Session對象的get方法就輕松檢索到了FriendProfile對象,傳遞回所需要的對象類型并過濾出查詢的字段——朋友的姓名。
結(jié)論
除去語法結(jié)構(gòu)與運行平臺的不同,使用Objective-C進(jìn)行iPhone開發(fā)與使用Java進(jìn)行網(wǎng)絡(luò)應(yīng)用開發(fā)在下面幾個方面是相同的:
◆兩種語言都是面向?qū)ο蟮?/p>
◆兩種語言使用同樣的設(shè)計模式,例如MVC
◆兩種語言使用相似的數(shù)據(jù)庫存儲技術(shù),例如ORM
然而,對于Java開發(fā)者,使用Objective-C時在有些地方要格外小心:
◆創(chuàng)建對象:Java對象是在運行時通過new關(guān)鍵字創(chuàng)建的。因此Java程序員無需擔(dān)心內(nèi)存分配問題。而在Objective-C中,一個對象可以由三個關(guān)鍵字創(chuàng)建,alloc、new或者copy,這三個關(guān)鍵字在創(chuàng)建對象時都會增加對象的持有計數(shù)(retain count),持有計數(shù)是Objective-C特有的內(nèi)存管理方法,顯示有多少個指針指向?qū)ο?#xff0c;是否可以被內(nèi)存管理器回收。
◆銷毀對象:由于強大的垃圾回收機制,Java的內(nèi)存管理工作極度簡單。Java的引用對象都存儲在JVM的堆內(nèi)存中,一旦不再被引用,就可以作為垃圾回收。Objective-C使用的是內(nèi)存管理器,而不是垃圾回收器。如果你使用上面說的三種方法在內(nèi)存中創(chuàng)建了一個對象,那么必須使用release方法來釋放對象。release方法會減少持有計數(shù),當(dāng)計數(shù)降到0時,被引用的對象會接受一個來自高級類的dealloc方法,釋放它占用的內(nèi)存并重新分配。如果忘記了釋放內(nèi)存或釋放失敗,那么會造成內(nèi)存泄露和不可預(yù)見的錯誤。
◆過多釋放和過早重新分配內(nèi)存:由于垃圾回收機制,Java程序員可以完全不考慮這些問題。但Objective-C程序員需要小心,不能釋放出比分配的更多的內(nèi)存。如果在已經(jīng)重新分配的對象上過多釋放內(nèi)存,就會造成應(yīng)用的崩潰。
上面這些例子說明了Objective-C和Java在語法和語言元素上有很多相同之處。更重要的是,它們解決問題的思路和用到的組件也是非常相似的。如果你是Java程序員,相信你在看完這篇文章后,轉(zhuǎn)向Objective-C的道路會更加通順。
【51CTO譯稿,非經(jīng)授權(quán)謝絕轉(zhuǎn)載,合作媒體轉(zhuǎn)載請注明原文出處、作者及51CTO譯者!】
【編輯推薦】
【責(zé)任編輯:立方TEL:(010)68476606】
總結(jié)
以上是生活随笔為你收集整理的objective-c java_程序员转型指南 当Java遇见了Objective-C的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 关闭虚拟机_如何使用Oracl
- 下一篇: python土木_土木和结构工程师用Py