14 October 2014

XCode、Objective-C、Cocoa说的是几样东西?

答案:三样东西。

XCode:你可以把它看成是一个开发环境,就好像Visual Studio或者Netbeans或者SharpDevelop一样的玩意。你可以将Interface Builder认为是Visual Studio中用来画界面的那部分功能单独提出来的程序。

Objective-C:这是一种语言,就好像c++是一种语言,Java是一种语言,c#是一种语言,莺歌历史也是一种语言一样。

Cocoa:是一大堆函数库,就好像MFC、.NET、Swing这类玩意,人家已经写好了一堆现成的东西,你只要知道怎么用就可以了。

有些人会比较容易混淆Objective-C和Cocoa,就好像有些人会混淆c#和.NET一样。这两个东西真的是两个不一样的东西。

Objective-C是什么?

你可以把它认为是语法稍稍有点不一样的c语言。虽然第一眼望上去你可能会认为它是火星语,和你所认知的任何一种语言都不一样。

先简单列出一点差别:

问题一:我在程序中看到大量的减号、中括号和NS**这种东西,他们是什么玩意儿?

  1. 减号(或者加号)

减号表示一个函数、或者方法、或者消息的开始,怎么说都行。

比如c#中,一个方法的写法可能是:

private void hello(bool ishello){
    //...
}

用Objective-C写出来就是

-(void) hello:(BOOL)ishello
{
    //...
}

挺好懂的吧?

不过在Objective-C里面没有public和private的概念,你可以认为全是public。

而用加号的意思就是其他函数可以直接调用这个类中的这个函数,而不用创建这个类的实例。

  1. 中括号

中括号可以认为是如何调用你刚才写的这个方法,通常在Objective-C里说“消息”。

比如C#里你可以这么写:

this.hello(true);

在Objective-C里,就要写成:

[self hello:YES];
  1. NS**

老乔当年被人挤兑出苹果,自立门户的时候做了个公司叫做NextStep,里面这一整套开发包很是让一些科学家们喜欢,而现在Mac OS用的就是NextStep这一套函数库。

这些开发NextStep的人们比较自恋地把函数库里面所有的类都用NextStep的缩写打头命名,也就是NS**了。比较常见的比如:

NSLog
NSString
NSInteger
NSURL
NSImage

问题二、#import、@interface这类玩意说的是什么?

  1. #import

你可以把它认为是#include,一样的。但是最好用#import,记住这个就行了。

  1. @interface等等

在Objective-C里写一个kids类:

先写一个kids.h文件定义这个类:

@interface Kids: NSObject {
	NSString *kidName;
	NSString *kidAge;
}
-(BOOL) isCaughtKid:;
@end

再写一个kids.m文件实现:

 
#import “kids.h”
@implementation Kids
-(void) init {
	kidName=@"mykid";
	kidAge=@"15";
}
 
-(BOOL) isCaughtKid:{
	return YES;
}
@end

这个写法也不一定对,主要是看看语法就行了。

####问题三、一个方法如何传递多个参数?

一个方法可以包含多个参数,不过后面的参数都要写名字。

多个参数的写法

(方法的数据类型) 函数名: (参数1数据类型) 参数1的数值的名字 参数2的名字: (参数2数据类型) 参数2值的名字 …. ;

举个例子,一个方法的定义:

-(void) setKids: (NSString *)myOldestKidName secondKid: (NSString *) mySecondOldestKidName thirdKid: (NSString *) myThirdOldestKidName;

实现这个函数的时候:

-(void) setKids: (NSString *)myOldestKidName secondKid: (NSString *) mySecondOldestKidName thirdKid: (NSString *) myThirdOldestKidName{
	大儿子 = myOldestKidName;
	二儿子 = mySecondOldestKidName;
	三儿子 = myThirdOldestKidName;
}

调用的时候:

	Kids *myKids = [[Kids alloc] init];
	[myKids setKids: @”张大力” secondKid: @”张二力” thirdKid: @”张小力”];

而如果你用java写这个方法,大致的写法可能是

public void setKids( string myOldestKidName, string mySecondOldestKidName, string myThirdOldestKidName)
{
…
}

调用的时候大概的写法可能是:

Kids myKids = new Kids();
myKids.setKids (“张大力”, “张二力”, “张小力”);

明白了吧?其实不怎么难看懂。

基本上,如果你能了解下面这段代码的转换关系,你Objective-C的语法也就懂了八成了:

[[[MyClass alloc] init:[foo bar]] autorelease];

转换成C#或者Java的语法也就是:

MyClass.alloc().init(foo.bar()).autorelease();

其他的一些东西

1、 id:

Objective-C有一种比较特殊的数据类型是id。你可以把它理解为“随便”。

在Objective-C里,一切东西都是指针形式保存,你获取到的就是这个对象在内存的位置。那么id就是你知道这个位置,但是不知道里面是啥的时候的写法。

2、 同一个数组可以保存不同的对象:

比如一个数组NSArray,这种数组里面可以保存各种不同的对象,比如这个数组里:

myArray <—-|
                   0: (float) 234.33f
                   1: @”我是个好人”
                   2: (NSImage *)  (俺的美图)
                   3: @”我真的是好人”

这是一个由4个东西组成的数组,这个数组包括一个浮点数,两个字符串和一个图片。

3、BOOL,YES,NO:

你可以认为YES表示C#或者Java里的true,NO表示false。而实际上YES是1,NO是0,BOOL本身就是个char。

4、IBOutlet、IBAction是啥玩意,总能看到。

这两个东西其实在语法中没有太大的作用。如果你希望在Interface Builder中能看到这个控件对象,那么在定义的时候前面加上IBOutlet,在IB里就能看到这个对象的outlet,如果你希望在Interface Builder里控制某个对象执行某些动作,就在方法前面加上(IBAction)。

而这两个东西实际上和void是一样的。

5、nil。

Objective-C里的NULL(空)就这么写,表示空指针。

6、为什么是@”字符串”而不是”字符串”

”字符串”是C的字符串,@””是把C的字符串转成NSString的一个简写. 在需要NSString的地方才需要这个转化,例如NSLog里面. 在需要C string的地方,还是用”字符串”的.

另外,@””这个转换是不支持中文的.例如NSLog(@”字符串”); 是一定输出不了中文的.

Objective-C语法

1.Object-c使用.m后缀作为代码文件的扩展名,当然你也可以使用.c和.cpp后缀名,但它们会分别调用C compiler和C++ compiler。Xcode作为iphone开发的集成环境,使用GCC作为编译器。

2.Object-c使用#import代替#include来导入声明文件。并且编译器保证#import不会被重复导入。

3.尽管Object-c也支持printf()进行控制台打印文本信息,但是更推荐使用NSLog(),并且它会自动在文本后面添加’/n’。

4.Object-c曾经也叫做NextStep,为了更好的体现其OOP的特性,NextStep里所有的对象都继承自NSObject,这点和Java的单根继承很类似。所以其Applicatio Kit里的类库前缀基本都是NS。而其Cocoa Foundation里的类库前缀基本都为NSCF

5.Object-c提供了BOOL类型,但这个BOOL类型和C++里的并不一样,在C++里一切非0值的东西都为true,而为0值的为false。但是Object-c里1为true并被宏定义为YES,0为false并被宏定义为NO。

所以,如果读者写下面的代码,肯定是错误的:

BOOL areIntsDifferent_faulty(int thing1,int thing2)

{

    return (thing1-thing2);

}

if(areIntsDifferent_faulty(23,5) == YES)

{

}

因为areIntsDifferent_faulty方法返回的是两个整数的差,如果这个差不为1,那么永远不会为YES。

6.Object-c里仍然继承了C语言的传统,其primitive type只有int、char、float、BOOL并用它们表达一切。

7.Object-c采用@interface来进行接口的声明,并采用@implementation对声明进行实现。

8.Object-c在Foundation Kit里提供了很多基础类库,常用的如NSString、NSRange、NSLog、NSPoint、NSRect等,这点和Symbian里提供的绘制接口很类似。

9.Object-c也支持Collection类库,并充分借鉴了Java Collection的设计,比如NSArray、NSMutableArray等。这些类库提供基本的插入、删除、排序操作,需要注意的是NSMutableArray才提供上述操作,而NSArray为不可修改的,这有点类似于Java的String和StringBuffer,而iphone里也提供了NSString和NSMutableString!

10.Object-c里采用跌代器的概念进行元素的遍历,NSEnumerator的典型用法如下:

NSEnumerator* enumerator;

enumerator = [array objectEnumerator];


id thingie;

while(thingie = [enumerator nextObject])

{

  NSLog(@"I found %@",thingie);

}

Objective-C的OO特性

1.继承

典型的继承用法如下:

@interface Circle : NSObject

{

   ShapeColor fillColor;

   ShapeRect  bounds;

}

-(void) setFillColor: (ShapeColor)fillColor;

-(void) setBounds: (ShapeRect)bounds;

-(void) draw;

@end //Circle

 

@interface Rectangle: NSObject

{

   ShapeColor fillColor;

   ShapeRect  bounds;

}

-(void) setFillColor: (ShapeColor)fillColor;

-(void) setBounds: (ShapeRect)bounds;

-(void) draw;

@end //Rectangle

上述两个类Circle、Rectangle的属性和行为非常类似,所以我们可以通过封装、继承的方法进行代码构造。如下:

 

@interface Shape: NSObject

{

   ShapeColor fillColor;

   ShapeRect bounds;

}



@implementation Shape

-(void) setFillColor:(ShapeColor)c

{

  fillColor = c;

}


-(void) setBounds:(ShapeRect)b

{

   bounds = b;

}


-(void)draw

{

 

}

@end //Shape

下面分别利用继承实现Circle和Rectangle,如下:

@interface Circle:Shape

@end //Circle

 
@implementation Circle

-(void) draw

{

  NSLog(@"drawing a circle");

}

@end //Circle

 


@interface Rectangle:Shape

@end //Rectangle


@implementation Rectangle


-(void) draw

{

  NSLog(@"drawing a rectangle");

}

 @end //Rectangle
 
 

2.多态

Object-c利用[super Init]之类的语法调用父类的方法,每个类都有一个指向自己的self指针,这点和C++的隐含this指针是类似的。

Object-c并不支持多继承,因为多继承的开销过大,需要解决虚基类的问题。

3.内存管理

Object-c在内存管理上也采用大多数编译器所采用的reference counting技术,亦即编译器为每个对象维护一个引用计数,在这个引用计数为0时释放对象所占用的资源。

当Java遇见了Objective-C

我们来看这个社交网络应用的例子,这个应用需要建立一个联系册,让你和朋友们时常保持联系。朋友的档案存储在FriendProfile对象中,包含四个字段:朋友的名字、城市、国家和电话号码,如Listing One所示:

Listing One  
//  FriendProfile.h  
#import <Foundation/Foundation.h>  
#import <UIKit/UIKit.h>  
 
@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的根类,大多数Objective-C中用到的类都会从中继承,这和Java中的Object类相似。接下来,我们分配多个NSString类型变量(等同于Java中的String类型)用来存储朋友的数据。

然后是建立FriendProfile类,使用@synthesize关键字自动创建各种get和set方法。

建立一个FriendProfile对象可以使用如下的语句:

FriendProfile * profile = [[FriendProfile alloc] init]; 

这里的alloc和init就像Java里的new关键字,用来在内存中建立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"; 

在Java中,如果我们想写一个FriendProfile类,所做的和Objective-C会非常相像,就像Listing Two所示:

Listing Two  
package com.vo;  
 
public class FriendProfile {  
   private String name;  
   private String country;  
   private String city;  
   private String phoneNbr;  
 
   public String getName() {  
      return name;  
   }  
 
   public void setName(String name) {  
     this.name = name;  
   }  
 
   public String getCountry() {  
      return country;  
   }  
 
   public void setCountry(String country) {  
      this.country = country;  
   }  
 
   public String getCity() {  
      return city;  
   }  
 
   public void setCity(String city) {  
      this.city = city;  
   }  
 
   public String getPhoneNbr() {  
      return phoneNbr;  
   }  
 
   public void setPhoneNbr(String phoneNbr) {  
      this.phoneNbr = phoneNbr;  
   }  
}  

Listing Two中提供了相似的字段,但是那些get和set必须清楚的写出来。现在我们看看怎样在通讯录里添加一个新朋友,参加Listing Three:

Listing Three   
public class FriendlyServletController extends HttpServlet {  
 
    private static final long serialVersionUID = 1L;  
 
    /**  
     * @see HttpServlet#doGet(HttpServletRequest request,   
     * HttpServletResponse response)  
     */ 
    protected void doGet(HttpServletRequest request,   
                         HttpServletResponse response)   
              throws ServletException, IOException {  
        doPost(request, response);  
    }  
 
    /**  
     * @see HttpServlet#doPost(HttpServletRequest request,   
     * HttpServletResponse response)  
     */ 
    protected void doPost(HttpServletRequest request,   
                          HttpServletResponse response)   
              throws ServletException, IOException {  
        response.setContentType("text/html");  
        PrintWriter out = response.getWriter();       
 
        final String 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  
            boolean validParameters =   
                    validateParameters(name, country, city, phoneNbr);  
            if (validParameters==false){  
                out.println(  
                   "please verify and submit correct information");  
                return;  
            }  
              
            FriendProfile newProfile = new FriendProfile();  
            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的客户端组件类,负责处理浏览器的请求。当用户登入网站并且决定添加一个朋友时,他会在HTML表单的字段中填入数据,表单提交时,Servlet收到并验证请求的参数,并创建一个FriendProfile对象,在内存中存储数据。而ProfileManager类会把你的FriendProfile对象存储到数据库中。

Objective-C的MVC模式

UIViewController实际上是一个控制器组件,用来触发业务逻辑,更新客户端的视图。

如果你想在Xcode中创建一个UIViewController类型的对象,可以选择通过XIB文件来创建。这种特殊的Xcode文件定义了图形用户界面或者说视图,包含了各种不同的控件,比如按钮、图表和标签等等。

回到我们的例子中来,假设你已经在联系列表中添加了几个朋友,现在想按下某个朋友的链接来看查看他的详细信息,这个功能可以通过定义控制器类来完成。代码请见Listing Four:

Listing Four  
//  FriendProfileViewController.h  
 
#import <UIKit/UIKit.h>  
 
@class FriendProfile;  
@class DatabaseController;  
@class MFriendProfile;  
 
// 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;  
}  

这段代码中,我们创建了一个FriendProfileViewController实例,在我们定义的View Bundle中进行初始化,显示出朋友的各种信息。

模型在装载视图时开始启动。每个控制器都有一些从父类UIViewController继承而来的生命周期方法。比如ViewdidLoad方法就是其中之一,它负责在视图装载之后的额外设置,从数据库中取出信息,更新视图。在最简单的情况下,我们的视图包含一系列标签,或者是UILabel类型的对象,可以在应用运行时设置各种文本,用户可以立即看见朋友信息被更新了。

Objective-C的数据库访问

苹果推荐开发者使用称为Core Data的Cocoa API框架进行数据库存取操作。Core Data框架能够直接与SQLite数据库相结合(我们例子中的数据库运行在移动设备上)。Core Data隐藏了复杂的SQL操作,取而代之的是非常方便的NSManagedObject界面,你可以直接操作整个对象实例的各种字段,这些字段可以自动存入数据库。Core Data框架的另一个方便之处是在数据库中创建表(以及向表中添加关联与限制),这些都可以在Core Data的用户界面中完成。

现在回到我们的社交网络应用例子,看看怎么从数据库中取出朋友的信息。我们使用SQLite 和Core Data API,但首先我们要稍微修改一下FriendProfile类,代码请见Listing Six:

Listing Six  
//FriendProfile.h interface file// MFriendProfile.h  
#import <Foundation/Foundation.h>  
#import <CoreData/CoreData.h>  
 
@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  
@dynamic name;  
@dynamic country;  
@dynamic city;  
@dynamic phoneNbr;  
 
@end 

这里的FriendProfile类与Listing One中的不同之处在于在这里我加入了Core Data框架的头文件。而且在这里我们的类是从NSManagedObject中扩展出来,带有了Core Data对象需要的全部基本行为。Core Data的NSManagedObject类中使用到的Accessor则在应用运行时动态创建。如果你想在FriendProfile类中声明或使用属性,但不想在编译时出现缺少方法的警告,可以使用@dynamic指令,而不是@synthesize指令。

使用NSManagedObject API有些复杂,但你理解之后就会变得很好用。Listing Seven是一个示例方法,从数据库的FRIENDPROFILE表中取得朋友的信息。表包含四列:NAME、COUNTRY、CITY和PHONE­NBR。

Listing Seven  
// DatabaseController.m  
#import "DatabaseController.h" 
#import <sqlite3.h>  
#define kDatabaseName @"SocialNetworking.sqlite" 
 
...  
 
- (NSManagedObject *)getFriendProfileObjectbyName:(NSString *)name {  
 
   managedObjectContext = [self managedObjectContext];    
 
   //create sort descriptors to specify preferred sort order 
   NSSortDescriptor *sortDescriptor =   
      [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];   
   NSArray *sortDescriptors =   
      [[NSArray alloc]  initWithObjects:sortDescriptor,nil];  
 
   //specify where clause   
   NSPredicate *predicate =   
      [NSPredicate predicateWithFormat:@"name == %d", name];      
 
    //fetch our friendís profile from database table   
    NSEntityDescription *entity =  
       [NSEntityDescription entityForName:@"MFRIENDPROFILE"   
        inManagedObjectContext:managedObjectContext];     
 
    NSFetchRequest *request = [[NSFetchRequest alloc] init];  
    [request setEntity:entity];  
 
    // Set the predicate for the current view 
    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 ([results count] > 0) {   
      return [results objectAtIndex:0];  
   }  
   return nil;  
}  

getFriendProfileObjectbyName方法把朋友的姓名作为一个参数接收过来。通过使用Core Data API,我们可以指定在哪一个表中进行查询和排序,并且在后台执行SQL语句。

SQL>select * from FriendProfile where name = "Albert"; 

Core Data API有许多种没有封装的“半成品”代码,可以访问NSManagedObjectContext、NSPersistentStoreCoordinator和NSManaged­ObjectModel对象。你可以复制这些代码,只要你取得了FriendProfile对象,就能以下面的形式取得它的属性:

NSString* name =        FriendProfile.name;  
NSString* country = FriendProfile.country;  
NSString* city =        FriendProfile.city;  
NSString* phoneNbr =    FriendProfile.phoneNbr; 

总的来说,Core Data是一个非常有用的功能,可以让你通过图表来定义数据表和管理,可以动态生成相应的对象,而且无需使用复杂的SQL语句。但不好的方面是这里有大量的没有经过封装的代码,这样你在使用它们与测试时需要非常小心。

结论

除去语法结构与运行平台的不同,使用Objective-C进行iPhone开发与使用Java进行网络应用开发在下面几个方面是相同的:

◆两种语言都是面向对象的

◆两种语言使用同样的设计模式,例如MVC

◆两种语言使用相似的数据库存储技术,例如ORM

然而,对于Java开发者,使用Objective-C时在有些地方要格外小心:

◆创建对象:Java对象是在运行时通过new关键字创建的。因此Java程序员无需担心内存分配问题。而在Objective-C中,一个对象可以由三个关键字创建,alloc、new或者copy,这三个关键字在创建对象时都会增加对象的持有计数(retain count),持有计数是Objective-C特有的内存管理方法,显示有多少个指针指向对象,是否可以被内存管理器回收。

◆销毁对象:由于强大的垃圾回收机制,Java的内存管理工作极度简单。Java的引用对象都存储在JVM的堆内存中,一旦不再被引用,就可以作为垃圾回收。Objective-C使用的是内存管理器,而不是垃圾回收器。如果你使用上面说的三种方法在内存中创建了一个对象,那么必须使用release方法来释放对象。release方法会减少持有计数,当计数降到0时,被引用的对象会接受一个来自高级类的dealloc方法,释放它占用的内存并重新分配。如果忘记了释放内存或释放失败,那么会造成内存泄露和不可预见的错误。

◆过多释放和过早重新分配内存:由于垃圾回收机制,Java程序员可以完全不考虑这些问题。但Objective-C程序员需要小心,不能释放出比分配的更多的内存。如果在已经重新分配的对象上过多释放内存,就会造成应用的崩溃。

上面这些例子说明了Objective-C和Java在语法和语言元素上有很多相同之处。更重要的是,它们解决问题的思路和用到的组件也是非常相似的。如果你是Java程序员,相信你在看完这篇文章后,转向Objective-C的道路会更加通顺。

objc

-EOF-