2010年11月27日星期六

Object-C编程规范

1.参考苹果的文档 “Coding Guidelines for Cocoa”
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html%23//apple_ref/doc/uid/10000146-SW1

2.Google的 “Google Objective-C Style Guide”
http://google-styleguide.googlecode.com/svn/trunk/objcguide.xml

3.Google的开源C++编程风格 "Google's Open Source C++ Style Guide"
http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
Share:

2010年11月10日星期三

IBOutlet 控件内存管理

在iphone中,只要控件使用IBOutlet连接 ,则必须释放它。无论它是否有@protety (retain)属性。

在mac os 中,如果控件使用IBOutlet连接,而无@property(retain)属性,则在dealloc不需要release。如果有retai属性,则需要释放

原因如下:

On Mac OS X, IBOutlets are connected like this:

  1. Look for a method called set<OutletName>:. If it exists call it.

  2. If no method exists, look for an instance variable named <OutletName>, set it without retaining.


On iPhone OS, IBOutlets are connected like this:

  1. call [object setValue:outletValue forKey:@"<OutletName>"]


The behavior of set value for key is to do something like this:

  1. Look for a method called set<OutletName>:. If it exists call it.

  2. If no method exists, look for an instance variable named , set it and retain it.


If you use a property, you'll fall into the "Look for a method called set<OutletName>:..." case on both platforms. If you just use an instance variable, then you'll have different retain/release behavior on Mac OS X VS iPhone OS. There's nothing wrong with using an instance variable, you just need to deal with this difference in behavior as you switch between platforms.

It is recommended you declare properties for all of your IBOutlets for clarity and consistency. The details are spelled out in the Memory Management Programming Guide. The basic gist is, when your NIB objects are unarchived, the nib loading code will go through and set all of the IBOutlets using setValue:forKey:. When you declare the memory management behavior on the property, there is no mystery as to what is going on. If the view gets unloaded, but you used a property that was declared as retain, you've still got a valid reference to your textfield.

Perhaps a more concrete example would be useful to indicate why you should use a retaining property:

I'm going to make some assumptions about the context in which you're working--I'll assume the UITextField above is a subview of another view that is controlled by a UIViewController. I will assume that at some point, the the view is off the screen (perhaps it is used in the context of a UINavigationController), and that at some point your application gets a memory warning.

So lets say your UIViewController subclass needs to access its view to display it on screen. At this point, the nib file will be loaded and each IBOutlet properties will be set by the nib loading code using setValue:forKey:. The important ones to note here are the top level view that will be set to the UIViewController's view property, (which will retain this top level view) and your UITextField, which will also be retained. If it is simply set, it'll have a retain put on it by the nib loading code, otherwise the property will have retained it. The UITextField will also be a subview of the top level UIView, so it will have an additional retain on it, being in the subviews array of the top level view, so at this point the text field has been retained twice.

At this point if you wanted to switch out the text field programmatically, you could do so. Using the property makes memory management more clear here; you just set the property with a new autoreleased text field. If you had not used the property, you must remember to release it, and optionally retain the new one. At this point it is somewhat ambiguous as to whom owns this new text field, because the memory management semantics are not contained within the setter.

Now let's say a different view controller is pushed on the UINavigation Controller's stack, so that this view is no longer in the foreground. In the case of a memory warning, the view of this offscreen view controller will be unloaded. At this point, the view property of the top level UIView will be nulled out, it will be released and deallocated.

Because the UITextField was set as a property that was retained, the UITextField is not deallocated, as it would have been had its only retain been that of the subviews array of the top level view.

If instead the instance variable for the UITextField not been set via a property, it'd also be around, because the nib loading code had retained it when setting the instance variable.

One interesting point this highlights is that because the UITextField is additionally retained through the property, you'll likely not want to keep it around in case of a memory warning. For this reason you should nil-out the property in the -[UIViewController viewDidUnload] method. This will get rid of the final release on the UITextField and deallocate it as intended. If using the property, you must remember to release it explicitly. While these two actions are functionally equivalent, the intent is different.

If instead of swapping out the text field, you chose to remove it from the view, you might have already removed it from the view hierarchy and set the property to nil, or released the text field. While it is possible to write a correct program in this case, its easy to make the error of over-releasing the text field in the viewDidUnload method. Over-releasing an object is a crash-inducing error; setting a property that is already nil again to nil is not.

My description may have been overly verbose, but I didn't want to leave out any details in the scenario. Simply following the guidelines will help avoid problems as you encounter more complex situations.

It is additionally worth noting that the memory management behavior differs on Mac OS X on the desktop. On the desktop, setting an IBOutlet without a setter does not retain the instance variable; but again uses the setter if available.
Share:

2010年10月10日星期日

在程序中添加Game Center功能

步骤:

1. 在iTunes Connect中启用Game Center。

2. 配置程序的Bundle identifier

3. 导入Game Kit Framework

4. 导入头文件<GameKit/GameKit.h>

5. 检测当前设备是否支持Game Center

6. 对于不支持Game Center的设备,对Game Kit Framework的引用应改为‘弱引用’(weak link)。

7. 程序启动后,认证用户。

一、iTunes Connect的配置

iTunes Connect Developer Guide

https://itunesconnect.apple.com/docs/iTunesConnect_DeveloperGuide.pdf

二、配置程序的Bundle identifier

com.myCompany.myCoolGame  与 iTunes Connect中配置相同

三、添加FrameWork (weak-link)检测当前设备是否支持Game Center

Target->’Get info’ ->’Genaral’ Linkd libray -> 将Required改为Weak

BOOL isGameCenterAvailable()

{

// Check for presence of GKLocalPlayer API.

Class gcClass = (NSClassFromString(@"GKLocalPlayer"));

// The device must be running running iOS 4.1 or later.

NSString *reqSysVer = @"4.1";

NSString *currSysVer = [[UIDevice currentDevice] systemVersion];

BOOL osVersionSupported = ([currSysVer compare:reqSysVer

options:NSNumericSearch] != NSOrderedAscending);

return (gcClass && osVersionSupported);

}

四、认证用户

用户必须具有账户才可以访问Game center。程序启动或在需要调用Game Center功能的地方,认证当前的使用账户。

- (void) authenticateLocalUser

{

if([GKLocalPlayer localPlayer].authenticated == NO)

{

[[GKLocalPlayer localPlayer] authenticateWithCompletionHandler:^(NSError *error)

{

if(error == nil)

{

//认证成功

}

else

{

//失败

UIAlertView* alert= [[[UIAlertView alloc] initWithTitle: @"Game Center Account Required"

message: [NSString stringWithFormat: @"Reason: %@", [error localizedDescription]]

delegate: self cancelButtonTitle: @"Try Again..." otherButtonTitles: NULL] autorelease];

[alert show];

}

}

];

}

}

五、排行榜功能

5.1 在iTunes Connect中配置排行榜

(得分格式、排行榜分类)等

5.2 将得分发送到Game Center

- (void) reportScore: (int64_t) score forCategory: (NSString*) category

{

GKScore *scoreReporter = [[[GKScore alloc] initWithCategory:category] autorelease];

scoreReporter.value = score;

[scoreReporter reportScoreWithCompletionHandler: ^(NSError *error)

{

if(error != nil)

{

//处理储物

}

else

{

//显示排行榜

}

}];

}

5.3 显示排行榜(LeaderboardController)

- (void) showLeaderboard

{

GKLeaderboardViewController *leaderboardController = [[GKLeaderboardViewController alloc] init];

if (leaderboardController != nil) {

leaderboardController.leaderboardDelegate = self;

[self presentModalViewController: leaderboardController animated: YES];

}

}

在显示leaderboard之前,可以配置leaderboard view Controller的一些属性。(category 属性,配置显示哪中分类下的排行榜;timeScope属性,配置显示哪个时间段内的排行榜)

//响应用户关闭排行榜的事件:

-(void)leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController

{

[self dismissModalViewControllerAnimated:YES];

}

5.4 获取排行榜数据,自定义排行榜显示的view

//获取所有用户

- (void) retrieveTopTenScores

{

GKLeaderboard *leaderboardRequest = [GKLeaderboard alloc] init];

if (leaderboardRequest != nil) {

leaderboardRequest.playerScope = GKLeaderboardPlayerScopeGlobal;

leaderboardRequest.timeScope = GKLeaderboardTimeScopeAllTime;

leaderboardRequest.range = NSMakeRange(1,10);

[leaderboardRequest loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {

if (error != nil)

// handle the error.

if (scores != nil)

// process the score information.

}];

}

//获取特定用户的排行榜数据

- (void) receiveMatchBestScores: (GKMatch*) match

{

GKLeaderboard *query = [GKLeaderboard alloc] initWithPlayers: match.players];

if (query != nil)

{

[query loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {

}

if (error != nil) // handle the error.

if (scores != nil) // process the score information.

}];

}

六、Cocos2d 中加入 Game Center

6.1 方式1 (直接获取数据、自定义排行榜的view)

6。2 0.99.5 sdk of cocos2d have a RootViewController

6.3 方式3  使用viewcontroller

创建一个viewcontroller 将其view属性添加到cocos2d的 glview


UIViewController *tempVC=[[UIViewController alloc] init];

GKMatchRequest *request = [[[GKMatchRequest alloc] init] autorelease];

request.minPlayers = 2;

request.maxPlayers = 2;

request.playersToInvite = playersToInvite;

GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithMatchRequest:request] autorelease];

mmvc.matchmakerDelegate = self;

[[[CCDirector sharedDirector] openGLView] addSubview:tempVC.view];

[tempVC presentModalViewController:mmvc animated:YES];

//响应事件

-(void)matchmakerViewControllerWasCancelled:(GKMatchmakerViewController *)viewController

{

[tempVC dismissModalViewControllerAnimated:YES];

[tempVC.view removeFromSuperview];

}

//退出时

-(void) onExit

{

[super onExit];

[tempVC release];

}

- (void) showLeaderboard

{

GKLeaderboardViewController *leaderboardController = [[[GKLeaderboardViewController alloc] init] autorelease];

if (leaderboardController != nil)

{

leaderboardController.leaderboardDelegate = self;

[[[CCDirector sharedDirector] openGLView] addSubview:tempVC.view];

[tempVC presentModalViewController:leaderboardController animated: YES];

}

}

- (void)leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController

{

[tempVC dismissModalViewControllerAnimated:YES];

[tempVC.view removeFromSuperview];

}

步骤:1. 在iTunes Connect中启用Game Center。2. 配置程序的Bundle identifier3. 导入Game Kit Framework4. 导入头文件<GameKit/GameKit.h>5. 检测当前设备是否支持Game Center6. 对于不支持Game Center的设备,对Game Kit Framework的引用应改为‘弱引用’(weak link)。7. 程序启动后,认证用户。
一、iTunes Connect的配置    iTunes Connect Developer Guide  https://itunesconnect.apple.com/docs/iTunesConnect_DeveloperGuide.pdf\r
二、配置程序的Bundle identifier
com.myCompany.myCoolGame  与 iTunes Connect中配置相同
三、添加FrameWork (weak-link)检测当前设备是否支持Game Center
Target->’Get info’ ->’Genaral’ Linkd libray -> 将Required改为Weak
BOOL isGameCenterAvailable(){
// Check for presence of GKLocalPlayer API. Class gcClass = (NSClassFromString(@"GKLocalPlayer"));// The device must be running running iOS 4.1 or later.
NSString *reqSysVer = @"4.1"; NSString *currSysVer = [[UIDevice currentDevice] systemVersion]; BOOL osVersionSupported = ([currSysVer compare:reqSysVeroptions:NSNumericSearch] != NSOrderedAscending);
return (gcClass && osVersionSupported);}















四、认证用户用户必须具有账户才可以访问Game center。程序启动或在需要调用Game Center功能的地方,认证当前的使用账户。
- (void) authenticateLocalUser{ if([GKLocalPlayer localPlayer].authenticated == NO) { [[GKLocalPlayer localPlayer] authenticateWithCompletionHandler:^(NSError *error)  { if(error == nil) { //认证成功 } else { //失败UIAlertView* alert= [[[UIAlertView alloc] initWithTitle: @"Game Center Account Required"  message: [NSString stringWithFormat: @"Reason: %@", [error localizedDescription]] delegate: self cancelButtonTitle: @"Try Again..." otherButtonTitles: NULL] autorelease]; [alert show]; } } ]; }}

五、排行榜功能5.1 在iTunes Connect中配置排行榜(得分格式、排行榜分类)等5.2 将得分发送到Game Center- (void) reportScore: (int64_t) score forCategory: (NSString*) category { GKScore *scoreReporter = [[[GKScore alloc] initWithCategory:category] autorelease]; scoreReporter.value = score; [scoreReporter reportScoreWithCompletionHandler: ^(NSError *error)  { if(error != nil) {    //处理储物 }  else      {        //显示排行榜 } }];}


5.3 显示排行榜(LeaderboardController)- (void) showLeaderboard{GKLeaderboardViewController *leaderboardController = [[GKLeaderboardViewController alloc] init];
if (leaderboardController != nil) { leaderboardController.leaderboardDelegate = self;  [self presentModalViewController: leaderboardController animated: YES]; }}


在显示leaderboard之前,可以配置leaderboard view Controller的一些属性。(category 属性,配置显示哪中分类下的排行榜;timeScope属性,配置显示哪个时间段内的排行榜)

//响应用户关闭排行榜的事件:
-(void)leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController  { [self dismissModalViewControllerAnimated:YES];  }


5.4 获取排行榜数据,自定义排行榜显示的view
//获取所有用户- (void) retrieveTopTenScores{ GKLeaderboard *leaderboardRequest = [GKLeaderboard alloc] init]; if (leaderboardRequest != nil) { leaderboardRequest.playerScope = GKLeaderboardPlayerScopeGlobal; leaderboardRequest.timeScope = GKLeaderboardTimeScopeAllTime; leaderboardRequest.range = NSMakeRange(1,10); [leaderboardRequest loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) { if (error != nil)  // handle the error. if (scores != nil) // process the score information.}];}
//获取特定用户的排行榜数据- (void) receiveMatchBestScores: (GKMatch*) match{ GKLeaderboard *query = [GKLeaderboard alloc] initWithPlayers: match.players]; if (query != nil) { [query loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {} if (error != nil) // handle the error. if (scores != nil) // process the score information.}];}
六、Cocos2d 中加入 Game Center

6.1 方式1 (直接获取数据、自定义排行榜的view)

6。2 0.99.5 sdk of cocos2d have a RootViewController

6.3 方式3  使用viewcontroller创建一个viewcontroller 将其view属性添加到cocos2d的 glview

UIViewController *tempVC=[[UIViewController alloc] init];

GKMatchRequest *request = [[[GKMatchRequest alloc] init] autorelease];

request.minPlayers = 2;request.maxPlayers = 2;

request.playersToInvite = playersToInvite;

GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithMatchRequest:request] autorelease];

mmvc.matchmakerDelegate = self;

[[[CCDirector sharedDirector] openGLView] addSubview:tempVC.view];

[tempVC presentModalViewController:mmvc animated:YES];

//响应事件

-(void)matchmakerViewControllerWasCancelled:(GKMatchmakerViewController *)viewController

{

[tempVC dismissModalViewControllerAnimated:YES];[tempVC.view removeFromSuperview];}
//退出时-(void) onExit

{

[super onExit];

[tempVC release];

}



- (void) showLeaderboard{GKLeaderboardViewController *leaderboardController = [[[GKLeaderboardViewController alloc] init] autorelease];

if (leaderboardController != nil)

{ leaderboardController.leaderboardDelegate = self;

[[[CCDirector sharedDirector] openGLView] addSubview:tempVC.view];

[tempVC presentModalViewController:leaderboardController animated: YES];

}

}
- (void)leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController

{

[tempVC dismissModalViewControllerAnimated:YES];

[tempVC.view removeFromSuperview];

}
Share:

2010年10月9日星期六

2010年10月4日星期一

2010年9月25日星期六

uiimage 扩展

- (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize;   //图片缩放裁剪


- (UIImage*)transformWidth:(CGFloat)width      height:(CGFloat)height; //变大小


+ (UIImage *)addImage:(UIImage *)image1 toImage:(UIImage *)image2; //合并图片


+ (UIImage *)imageFromImage:(UIImage *)image inRect:(CGRect)rect; //裁剪部分图片


+ (void)imageSavedToPhotosAlbum:(UIImage *)image


didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo;  //保存图片到媒体库


UIImageExtrasUIImageExtra




关于图片缩放的线程安全和非线程安全操作.


线程安全的操作只能在主线程中进行操作,对于大图片的处理肯定会消耗大量的时间,如下面的方法


方法 1 使用 UIKit


+ (UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize;


{


// Create a graphics image context


UIGraphicsBeginImageContext(newSize);


 


// Tell the old image to draw in this new context, with the desired


// new size


[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];


 


// Get the new image from the context


UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();


 


// End the context


UIGraphicsEndImageContext();


 


// Return the new image.


return newImage;


}


此方法很简单, 但是这种方法不是线程安全的情况下.


方法 2 使用 CoreGraphics


+ (UIImage*)imageWithImage:(UIImage*)sourceImage scaledToSize:(CGSize)newSize;


{


CGFloat targetWidth = targetSize.width;


CGFloat targetHeight = targetSize.height;


 


CGImageRef imageRef = [sourceImage CGImage];


CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);


CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);


 


if (bitmapInfo == kCGImageAlphaNone) {


bitmapInfo = kCGImageAlphaNoneSkipLast;


}


 


CGContextRef bitmap;


 


if (sourceImage.imageOrientation == UIImageOrientationUp || sourceImage.imageOrientation == UIImageOrientationDown) {


bitmap = CGBitmapContextCreate(NULL, targetWidth, targetHeight, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);


 


} else {


bitmap = CGBitmapContextCreate(NULL, targetHeight, targetWidth, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);


 


}


 


if (sourceImage.imageOrientation == UIImageOrientationLeft) {


CGContextRotateCTM (bitmap, radians(90));


CGContextTranslateCTM (bitmap, 0, -targetHeight);


 


} else if (sourceImage.imageOrientation == UIImageOrientationRight) {


CGContextRotateCTM (bitmap, radians(-90));


CGContextTranslateCTM (bitmap, -targetWidth, 0);


 


} else if (sourceImage.imageOrientation == UIImageOrientationUp) {


// NOTHING


} else if (sourceImage.imageOrientation == UIImageOrientationDown) {


CGContextTranslateCTM (bitmap, targetWidth, targetHeight);


CGContextRotateCTM (bitmap, radians(-180.));


}


 


CGContextDrawImage(bitmap, CGRectMake(0, 0, targetWidth, targetHeight), imageRef);


CGImageRef ref = CGBitmapContextCreateImage(bitmap);


UIImage* newImage = [UIImage imageWithCGImage:ref];


 


CGContextRelease(bitmap);


CGImageRelease(ref);


 


return newImage;


}


这种方法的好处是它是线程安全,加上它负责的 (使用正确的颜色空间和位图信息,处理图像方向) 的小东西,UIKit 版本不会。


如何调整和保持长宽比 (如 AspectFill 选项)?


它是非常类似于上述,方法,它看起来像这样:


+ (UIImage*)imageWithImage:(UIImage*)sourceImage scaledToSizeWithSameAspectRatio:(CGSize)targetSize;


{


CGSize imageSize = sourceImage.size;


CGFloat width = imageSize.width;


CGFloat height = imageSize.height;


CGFloat targetWidth = targetSize.width;


CGFloat targetHeight = targetSize.height;


CGFloat scaleFactor = 0.0;


CGFloat scaledWidth = targetWidth;


CGFloat scaledHeight = targetHeight;


CGPoint thumbnailPoint = CGPointMake(0.0,0.0);


 


if (CGSizeEqualToSize(imageSize, targetSize) == NO) {


CGFloat widthFactor = targetWidth / width;


CGFloat heightFactor = targetHeight / height;


 


if (widthFactor > heightFactor) {


scaleFactor = widthFactor; // scale to fit height


}


else {


scaleFactor = heightFactor; // scale to fit width


}


 


scaledWidth  = width * scaleFactor;


scaledHeight = height * scaleFactor;


 


// center the image


if (widthFactor > heightFactor) {


thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;


}


else if (widthFactor < heightFactor) {


thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;


}


}


 


CGImageRef imageRef = [sourceImage CGImage];


CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);


CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);


 


if (bitmapInfo == kCGImageAlphaNone) {


bitmapInfo = kCGImageAlphaNoneSkipLast;


}


 


CGContextRef bitmap;


 


if (sourceImage.imageOrientation == UIImageOrientationUp || sourceImage.imageOrientation == UIImageOrientationDown) {


bitmap = CGBitmapContextCreate(NULL, targetWidth, targetHeight, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);


 


} else {


bitmap = CGBitmapContextCreate(NULL, targetHeight, targetWidth, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);


 


}


 


// In the right or left cases, we need to switch scaledWidth and scaledHeight,


// and also the thumbnail point


if (sourceImage.imageOrientation == UIImageOrientationLeft) {


thumbnailPoint = CGPointMake(thumbnailPoint.y, thumbnailPoint.x);


CGFloat oldScaledWidth = scaledWidth;


scaledWidth = scaledHeight;


scaledHeight = oldScaledWidth;


 


CGContextRotateCTM (bitmap, radians(90));


CGContextTranslateCTM (bitmap, 0, -targetHeight);


 


} else if (sourceImage.imageOrientation == UIImageOrientationRight) {


thumbnailPoint = CGPointMake(thumbnailPoint.y, thumbnailPoint.x);


CGFloat oldScaledWidth = scaledWidth;


scaledWidth = scaledHeight;


scaledHeight = oldScaledWidth;


 


CGContextRotateCTM (bitmap, radians(-90));


CGContextTranslateCTM (bitmap, -targetWidth, 0);


 


} else if (sourceImage.imageOrientation == UIImageOrientationUp) {


// NOTHING


} else if (sourceImage.imageOrientation == UIImageOrientationDown) {


CGContextTranslateCTM (bitmap, targetWidth, targetHeight);


CGContextRotateCTM (bitmap, radians(-180.));


}


 


CGContextDrawImage(bitmap, CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledWidth, scaledHeight), imageRef);


CGImageRef ref = CGBitmapContextCreateImage(bitmap);


UIImage* newImage = [UIImage imageWithCGImage:ref];


 


CGContextRelease(bitmap);


CGImageRelease(ref);


 


return newImage;


}

Share:

2010年8月16日星期一

IBOutlet变量的生命周期 IBOutlet怎么会是nil呢?

当使用initWithNibName 初始化viewController时,发现IBoutlet修饰的变量为 nil。原因是该viewController或view没有加载到当前视图中,不处于活动状态。

类似的一个情况: http://blog.prosight.me/index.php/tag/iboutlet
今天遇到一个问题困扰了很久。 代码如下:

1.

2. FileOverviewViewController *fileOverviewViewController = [[FileOverviewViewController alloc] initWithNibName:@"FileOverviewView" bundle:nil];

3. // AAAAA

4. [self.navigationController pushViewController:fileOverviewViewController animated:YES];

5. // BBBBBB

6.

如果你有这个Controller中的view里面有IBOutlet的变量,如果你在A的地方进行赋值或者其他操作的话,界面将不会有任何更新,那些IBoutlet变量的值都为NULL, 如果在B处设置就可以正常显示了。


结论: 如果你使用navigation Controller的话, 一定要在push了这个ViewController之后再操作这个ViewController中的IBOutlet变量,否则这个变量会因为不在作用范围内而无法操作。


扩展开来也就是说只有当一个ViewController被载入处于活动状态的时候,这个ViewController中的IBOutlet变量才能正常使用,否则都会因为不在作用范围内而无法正常使用的

如果不使用navigation Controlle的话,必须在

[XXView addSubview:fileOverviewViewController.view]后再使用IBoutlet变量
Share:

2010年8月11日星期三

自定义NSURLProtocol


NSURL类,提供了操作URLs和URL所指向资源的能力。基础框架同样提供了一系列方法实现url加载、cookie存储、response的缓存、凭据的存储和认证。

框架默认提供了对以下四种协议的资源访问:

The URL loading system provides support for accessing resources using the following protocols:

▪  File Transfer Protocol (ftp://)

▪  Hypertext Transfer Protocol (http://)

▪  Secure 128-bit Hypertext Transfer Protocol (https://)

Local file URLs (file:///)

为了扩展对其他协议的支持,我们可以扩展NSURLProtocol类。

以下例子演示如果对自定义的特殊URL进行操作如<img src=”special:///Special%20Example” id=”stringimage”>,定义了一个特殊的协议”special:///“。当使用UIWebView加载还有该定义的html内容时,我们可以在自己的程序中进行处理。

@interface SpecialProtocol : NSURLProtocol {

}

+ (void) registerSpecialProtocol;

@end

@implementation SpecialProtocol

+ (void) registerSpecialProtocol {

static BOOL inited = NO;

if ( ! inited ) {

[NSURLProtocol registerClass:[SpecialProtocol class]];

inited = YES;

}

}

//判断协议是否收到支持

+ (BOOL)canInitWithRequest:(NSURLRequest *)theRequest {

MLOG(@”%@ received %@ with url=’%@’ and scheme=’%@’”,

self, NSStringFromSelector(_cmd),

[[theRequest URL] absoluteString], [[theRequest URL] scheme]);

/* get the scheme from the URL */

NSString *theScheme = [[theRequest URL] scheme];

/* return true if it matches the scheme we’re using for our protocol. */

return ([theScheme caseInsensitiveCompare: [SpecialProtocol specialProtocolScheme]] == NSOrderedSame );

}

- (void)startLoading {

/* calculate the size of the rendered string */

NSSize tsz = [theString sizeWithAttributes:fontAttrs];

/* allocate an NSImage with large dimensions enough to draw the entire string. */

NSImage *myImage = [[[NSImage alloc] initWithSize: tsz] autorelease];

/* draw the string into the NSImage */

[myImage lockFocus];

[theString drawAtPoint:NSMakePoint(0,0) withAttributes:fontAttrs];

[myImage unlockFocus];

/* retrieve the jfif data for the image */

NSData *data = [myImage JFIFData: 0.75];

/* create the response record, set the mime type to jpeg */

NSURLResponse *response =

[[NSURLResponse alloc] initWithURL:[request URL]

MIMEType:@”image/jpeg”

expectedContentLength:-1

textEncodingName:nil];

/* get a reference to the client so we can hand off the data */

id<NSURLProtocolClient> client = [self client];

/* turn off caching for this response data */

[client URLProtocol:self didReceiveResponse:response

cacheStoragePolicy:NSURLCacheStorageNotAllowed];

/* set the data in the response to our jfif data */

[client URLProtocol:self didLoadData:data];

/* notify that we completed loading */

[client URLProtocolDidFinishLoading:self];

/* we can release our copy */

[response release];

/* if an error occured during our load, here is the code we would

execute to send that information back to webKit.  We’re not using it here,

but you will probably want to use this code for proper error handling.  */

if (0) { /* in case of error */

int resultCode;

resultCode = NSURLErrorResourceUnavailable;

[client URLProtocol:self didFailWithError:[NSError errorWithDomain:NSURLErrorDomain

code:resultCode userInfo:nil]];

}

/* added the extra log statement here so you can see that stopLoading is called

by the underlying machinery before we leave this routine. */

-    MLOG(@”%@ received %@ – end”, self, NSStringFromSelector(_cmd));

- }

==============

自定义NSURLProtocol后,如何使用

1。在程序中注册

[SpecialProtocol registerSpecialProtocol];

2.访问特殊协议的url

如通过webview 加载html,html中含有sepcial://的特殊url

[[theWebView mainFrame] loadHTMLString:mainWebPage baseURL:nil];

另外一种方法:

NSString *theURLString = [NSString stringWithFormat:@"specail://%@/", thePath];

NSURL *theURL = [NSURL URLWithString:theURLString];

[xxx initWithContentsOfURL: theURL];

3. 遇到匹配的协议时,会调用 SpecialProtocol 判断该协议是否支持

4.   在 startLoading 方法中处理对特殊协议的请求

自定义NSURLProtocol 适用范围

定义自己的文件格式 在程序中注册特殊的url,当访问url时特殊处理

代码示例可以参考apple的示例: SpecialPictureProtocol
Share:

2010年7月25日星期日

iso 4 中textFieldShouldBeginEditing的问题

在ios 4 中textFieldShouldBeginEditing,会调用两次。如果有需要在textFieldShouldBeginEditing处理的时间时,需要添加一个BOOL变量来检查是否 已经触发该事件。以免导致莫名其妙的问题。

一般都是在此事件中return NO,然后自定义一个ActionSheet 或者AlertView。当你发现ActionSheet或AlertView显示很诡异时,检查一下是不是被调用两次了。
Share:

2010年7月9日星期五

iphone 中发送短信代码(ios 4)

//MFMessageComposeViewController 只在ios 4.0 后可用

Class smsClass = NSClassFromString(@"MFMessageComposeViewController");
if (smsClass != nil){

  if ([smsClass canSendText]){
    [self displaySMSComposerSheet];
  }
 else {
     [self launchSmsAppOnDevice];
 }
}
else {
  [self launchSmsAppOnDevice];
}

-(void)launchSmsAppOnDevice
{
  UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
  pasteboard.string =@"sms body";
  [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"sms:// "]];
}

#pragma mark -
#pragma mark Componse sms

-(void)displaySMSComposerSheet
{

  MFMessageComposeViewController *picker = [[MFMessageComposeViewController alloc] init];
  picker.body = "sms body";
  picker.messageComposeDelegate = self;
  [self presentModalViewController:picker animated:YES];
  [picker release];
}

- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
{
  [self dismissModalViewControllerAnimated:YES];
}
Share:

2010年5月31日星期一

NSOperation NSOperationQueue

The NSOperation and NSOperationQueue classes alleviate much of the pain of multi-threading, allowing you to simply define your tasks, set any dependencies that exist, and fire them off. Each task, or operation, is represented by an instance of an NSOperation class; the NSOperationQueue class takes care of starting the operations, ensuring that they are run in the appropriate order, and accounting for any priorities that have been set.

NSOperation 和 NSOperationQueue类简化了多线程操作。创建一个NSOperationQueue对象,然后创建NSOperation添加到NSOperationQueue中。NSOperationQueue会为每一个NSOperation创建一个线程,并按照它们被添加的顺序执行(或者指定的顺序)。NSOperationQueue会自己处理autorelease pools 和其他的garbage,而不需要像在自己手动创建多线程时去费心管理这些事情。

NSOperationQueue *queue = [NSOperationQueue new];

NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(methodToCall)
object:objectToPassToMethod];

[queue addOperation:operation];
[operation release];


methodToCall会在新线程中被执行。


Share:

2010年5月12日星期三

modal view 上显示 navigation bar

向下实例显示modeview时不会显示上方的navigation bar

ModalViewController *modal = [[ModalViewController alloc] init];
[self presentModalViewController:model animated:YES];
[modal release];

需要这么实用才可以


ModalViewController *modal = [[ModalViewController alloc] init];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:modal];
[self presentModalViewController:nav animated:YES];
[modal release];

Share:

2010年5月7日星期五

iphone core data 基础操作

1. 插入

AppDelegate *app = [[UIApplication sharedApplication] delegate];

NSManagedObjectContext *context = [app managedObjectContext];

NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:@"entityname" inManagedObjectContext:context];

[newManagedObject setValue:value forKey:@"propertyname"];

NSError *error; if (![context save:&error]) {

// Handle the error...

}

//查询
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

NSManagedObjectContext *managedObjectContext = appDelegate.managedObjectContext;

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Hero" inManagedObjectContext:managedObjectContext];

NSSortDescriptor *sortDescriptor1 = [[NSSortDescriptor alloc]

initWithKey:@"name" ascending:YES];

NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc]

initWithKey:@"secretIdentity" ascending:YES];

NSArray *sortDescriptors = [[NSArray alloc]

initWithObjects:sortDescriptor1, sortDescriptor2, nil];

[fetchRequest setSortDescriptors:sortDescriptors];

[fetchRequest setEntity:entity];

[fetchRequest setFetchBatchSize:20];

NSArray *objecs = [context executeFetchRequest: fetchRequest error:&error];

//删除

NSManagedObjectContext *managedObjectContext = appDelegate.managedObjectContext;

[context deleteObject:[objecs objectIndex:index];

// Save the context.

NSError *error; if (![context save:&error]) {

// Update to handle the error appropriately.

NSLog(@"Unresolved error %@, %@", error, [error userInfo]);

exit(-1); // Fail

}

//属性

NSManagedObject *managedObject;

NSString *keypath;

NSString *labelString;

NSString *currentValue = [self.managedObject valueForKeyPath:self.keypath];

NSEntityDescription *ed = [self.managedObject entity];

NSDictionary *properties = [ed propertiesByName];

NSAttributeDescription *ad = [properties objectForKey:self.keypath];

NSString *defaultValue = nil;

if (ad != nil)

defaultValue = [ad defaultValue];

//core data relation  查询 或 修改

NSManagedObject *child = [NSEntityDescription insertNewObjectForEntityForName: @"Person" inManagedObjectContext:thePerson.managedObjectContext];

NSMutableSet *children = [person mutableSetValueForKey:@"children"]; //查询,可修改

[children addObject:child];

[children removeObject:childToBeRemoved];

[[children managedObjectContext] deleteObject:childToBeRemoved]; //真正的删除




NSSet *children = [person valueForKey:@"children"]; //查询,不可修改

for (NSManagedObject *oneChild in children) {

// do something

}

补充:

1 是否将图片存储到Core Data中,以及NSData如何存储的一些规则

First, always store your images in a usable format such as PNG or JPEG instead of NSData. This will save you a lot of headaches.

Second, the rule for storing binary data is:

  • < 100kb store in the same table as the relevant data

  • < 1mb store in a separate table attached via a relationship to avoid loading unnecessarily

  • > 1mb store on disk and reference it inside of Core Data

(1。图片尽量保存为文件 2。<100k 和相关数据保存在一张表中  <1M保存在单独的一张表中 >1M保存到磁盘文件)
Share:

Objective-C runtime

#import <objc/runtime.h>

#import <objc/message.h>

This is the first time we’ve worked with the Objective-C runtime directly. Although for most programming jobs there’s no need to dive down into the runtime, having access to the same functions that are used to implement Objective-C gives us an incredible amount of power. Let’s quickly run through what we’re doing here, but don’t feel like you have to grok this one the first time through.
First, we declare an int, which will hold the number of properties that managedObject has. Then we declare a pointer to an objc_property_t, which is a datatype that represents Objective-C 2.0 properties, and use a runtime function called class_copyPropertyList() to retrieve the list of pointers to the managedObject properties. This function also populates outCount with the number of properties.

unsigned int outCount; objc_property_t *propList =

class_copyPropertyList([self.managedObject class], &outCount); Next, we use a for loop to iterate over the properties:

for (int i=0; i < outCount; i++)

{

We grab a reference to the structure that points to one property in the list, and then get the property’s name as an NSString instance. We also get the property’s attributes, which are contained in a string. The format for the attribute string is documented in Apple’s Objective-C runtime documentation, but for our purposes, all we need to know

is that it contains (among other things) the class of the property.

We check to see if the attribute string contains @"NSSet":

if ([attrs rangeOfString:@"NSSet"].location != NSNotFound) {

If it does, we then retrieve the set and create an instance of NSMutableArray to keep track of the objects that need to be deleted. It is not safe to delete objects from a collection while we are iterating over it, so we’ll stick them in an array. Then, when we’re finished iterating, we’ll iterate through the array of objects that need to be deleted and remove them.

}

}

NSMutableSet *objects = [self.managedObject valueForKey:propName];

NSMutableArray *toDelete = [NSMutableArray array]; for (NSManagedObject *oneObject in objects) {

if ([oneObject isDeleted]) [toDelete addObject:oneObject];

} for (NSManagedObject *oneObject in toDelete) {

}

[objects removeObject:oneObject]; NSError *error; if (![self.managedObject.managedObjectContext save:&error])

NSLog(@"Error saving: %@", [error localizedDescription]);

}
Share:

2010年4月29日星期四

用nib文件创建自定义uiview uitableviewcell 等


有好多同学习惯于在uiview的initwithfram方法中添加自定义的控件,如果要添加的控件较多,位置调整就会很麻烦。
我更习惯于使用interface builder来创建nib文件,在nib文件上拖动控件,可以方便迅速的构建自定义的新view等。
步骤:
1。添加新文件 cocoa touch class, 创建一个新类继承自UIVIEW ,命名位UIMyView
2。添加新文件 user interface, 创建Empty xib文件 ,命名MyView.xib
3.打开MyView.xib ,从library中选择view,拖动到Myview.xib 中。
4。双击添加的view,此时可以修改view的大小等属性 。在第四个窗口中修改view的Class为UImyView,这样,用nib创建的view就会和自己定义的新类相关联
5。使用UIMyView
NSArray *array = [[NSBundle mainBundle] loadNibNamed:@”MyView” owner:self options:nil];
UIMyView *view = [array objectAtIndex:0];
Share:

2010年4月28日星期三

iPhone-屏幕截取

一、从View生成图片
-(void)captureScreen{
  // Begin
  UIGraphicsBeginImageContext(CGSizeMake(320,480));
  // Render
  CGContextRef ref = UIGraphicsGetCurrentContext(); 
  [self.view.layer renderInContext:ref];
  // Capture
  UIImage *tmpImage = UIGraphicsGetImageFromCurrentImageContext();
  // Display test
  //imgView.image = tmpImage;
  // nil test
  if (tmpImage == nil) {
    NSLog(@"nil returned");
  }
  // Size test
  //NSLog(@"size %f,%f",imgView.image.size.width,imgView.image.size.height);
  // Save
  //NSData *dataObj = UIImagePNGRepresentation(tmpImage);
  //[dataObj writeToFile:@"/Users/kiichi/Desktop/test1.png" atomically:NO];
  // Save 2
  //UIImageWriteToSavedPhotosAlbum(tmpImage,nil,nil,nil);
  UIImageWriteToSavedPhotosAlbum(tmpImage, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
  // End
  UIGraphicsEndImageContext();
}


- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo{
 //mSpining.hidden = true;
 if (error == nil) {
  UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" message:@"Image has been saved"
                delegate:self cancelButtonTitle:@"OK" otherButtonTitles: nil];
  [alert show];
  [alert release];
 }
 else {
  UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" 
                                                  message:[NSString stringWithFormat:@"ERROR: %@", [error localizedDescription]]
                                                 delegate:self 
                                        cancelButtonTitle:@"OK" 
                                        otherButtonTitles: nil];
  [alert show];
  [alert release];

 }
}
二、Screen Capture from the top level
(可以截取最顶层的屏幕图片,甚至可以截取摄像头的缓冲屏幕图片) To capture entire screen from the top level, even including the camera buffer:
1. Change file name to .mm from .m
2. Add extern

extern "C" CGImageRef UIGetScreenImage(); //私有api (官方已经允许使用,官方论坛声明地址:https://devforums.apple.com/message/149553)

3. Call UIGetScreenImage

  CGImageRef iref =  UIGetScreenImage();
  UIImage *tmpImage = [[UIImage alloc] initWithCGImage:iref];

Share:

2010年4月22日星期四

iphone 开发小技巧


1。给iPhone程序创建Splash欢迎界面

最简单的方法就是做一个全屏的欢迎页的图片,把它命名为Default.png,然后放在Xcode工程的Resource里面。 执行就可以看到你的这个默认图像在程序完全加载之前显示在屏幕上。

Default.png是一张480*320的png图片用于在程序启动时显示。启动时,系统会用这张图片作为临时背景,直到程序载入了他的窗口和用户界面。

Icon.png是一张57*57的png图片,用于在iPhone的主界面上作为程序图标代表你的程序。这张图片不需要有其他附加特效,系统会自动添加这些效果。

Icon-Setting.png是一张29*29的png图片,用于在设置程序中作为图标代表你的程序。如果你的程序有Settings.bundle,这个图标将会显示在程序名的旁边。如果你没有设置这张图片,系统会将Icon.png缩放来代替。

2。 怎样才能让程序在运行过程中不锁屏呢?

[UIApplication sharedApplication].idleTimerDisabled=YES;//not let iphone go to sleep

3。显示被view 或 control遮盖的背景内容

xx.backgroundColor=[UIColor clearColor];

4。url编码

NSString *strURL = @”http://www.google.com/search?hl=en&newwindow=1&q=如何对url编码&aq=f&oq=&aqi=”;

strURL = [strURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; //使用utf8

strURL=[strURLstringByAddingPercentEscapesUsingEncoding: CFStringConvertEncodingToNSStringEncoding( kCFStringEncodingGB_18030_2000)] ;////使用 gb2312

5。转换网页编码gb2312 -> utf

//编码转换 gb2313 to UTF
NSData * myResponseData = [myRequest responseData];
NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding (kCFStringEncodingGB_18030_2000);
NSString * myResponseStr = [[NSString alloc] initWithData:myResponseData encoding:enc];
6。获取界面语言设置

NSUserDefaults* defs = [NSUserDefaults standardUserDefaults];
NSArray* languages = [defs objectForKey:@"AppleLanguages"];
NSString* preferredLang = [languages objectAtIndex:0];

7.对于做为数据Model的类来说,让其实现NSCoding协议是个好习惯

it’s just good habit to conform data model classes to NSCoding.

8

It’s okay to redefine properties to be more permissive than the

same property as declared in a protocol to which you’ve conformed, or as declared in

your superclass. You can always redefine a readonly or writeonly property to be

readwrite, but you have to explicitly use the readwrite keyword. Most of the time, that

keyword isn’t used because it’s the default value and unnecessary.
Share:

iPhone开发中内存的合理使用(转)

iPhone 开发过程中,内存的使用至关重要。不但要合理分配使用内存,还要注意内存泄露的问题, 因为内存泄露会导致程序由于内存不足而崩溃。根据个人开发的经验来看,在开发iPhone程序的过程中,关于内存的问题需要注意以下几点:

  1. 内存分配、释放成对出现
    使用 alloc 分配的内存对象需要在用完后 调用release释放

  2. 注意copy,retain,assign操作符的区别
    copy, retain操作符赋值的对象和alloc一样,需要release释放,否则会导致内存泄露
    assign 操作符的含义是将对象指向另一对象, 两者指向的是同一内存对象,无需调用release释放 

  3. NSArray, NSDictionary, NSMutableArray, NSMutableDictionary等容器类, 在使用这些容器类的时候要注意, 在添加对象到这些类对象时,容器类会自动调用一次retain,比如
    NSString* string  = [[NSString alloc] initWithString:@”test string”];  // refCount = 1
    NSArray* array = [NSArray array];
    [array addObject:string]; // refCount = 2
    [string release]; // refCount = 1
    这种情况, 即便string已经调用release,但是在加入 array中时已经调用了一次retain,注意refCount的变化 简单介绍一下iPhone 或者说Objective C对对象的管理机制。 OC中采用一种引用计数refCount的方式来管理内存对象,当refCount等于0的时候就会释放对象所占的内存, 操作符alloc,copy, retain都会将refCount加1表示引用计数增加, 而调用release使 refCount自动减1, 当refCount=0时表示该对象已经没有被引用,可以将其释放, 之后该对象便不可用

  4. 连续重复分配内存的过程最好创建自己的自动释放池 NSAutoreleasePool,通常是在for、while等循环操作过程中,比如
    for( int i=0; i < 100; i++ )
    {
    NSString* str = [[NSString alloc] initWithString:@”some string”];
    // 针对str的操作
    [str release];
    }
    在这种情况下,有2点需要注意,首先如果可能,就把str的分配、释放放在for循环外面, 从而减少内存的分配、释放导致程序效率低下,也利于内存回收,如上例应该为
    NSString* str = [[NSString alloc] initWithString:@”some string”];
    for( int i=0; i < 100; i++ )
    {
    // 针对str的操作
    }
    [str release];
    如果实际情况复杂,不能像例子中那样抽离出循环外,需要创建自己的内存管理池, 同样适用于需要大量autorelease对象的过程
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    for(int i=0; i < 100; i++ )
    {
    // actions
    }
    [pool release];
    之所以要这样做,是因为apple处理iPhone的内存管理机制问题, 通常情况下,系统会在需要的时候释放整理所有的autorelease对象,这就是为什么有时候autorelease对象在作用域范围外还有可能是有效的

  5. 避免不常用对象驻留内存, 桌面开发的tx很多喜欢在程序初始化的时候将某些资源比如小图片加载进内存,从而提高程序运行效率。 但这种方式在iPhone以及其它mobile移动设备开发时需要避免,因为对于这些设备来说,内存永远显得不足(当然普通pc内存也是越大越好:) )。 按照apple的官方说法, Load resources lazily . 就是在需要的时候再从硬盘上读取,而避免常驻内存。


原文链接:http://www.flyblog.info/catprogramming/168.html
Share:

2010年4月17日星期六

xcode中object-c c++混编出现的问题

error: expected unqualified-id before'@' ,出现一大堆的错误

出现这种情况的原因是xcode无法分辨出,要编译的文件类型 是c++ 还是 object-c++ ,所以默认使用object-c 或是 c++进行编译。这样就会导致类型错误,很多东西未定义

错误情况: object-c代码中使用c++代码

或者c++代码中使用object-c 代码

解决情况

如果是在object-c中使用c++代码,则将.m 文件名改为.mm ,另外在文件名上右键-Get info-》将文件类型改为 sourcecode.cpp.objcpp

如果是在c++类中引用object-c代码,则在文件名上右键-Get info-》将文件类型改为 sourcecode.cpp.objcpp

--------------

XCode Error ".objc_class_name_XXX", referenced from: 错误解决

某源文件在主target里面没有加进来,引用这个文件就会出现标题所示的错误,解决方法是找到这个文件,把后面的勾打上(加入到这个target里面来).

在文件上右键 -getinfo-》targets-》将属于的target打上勾

Linking Error: Symbol Not Found


错误的几种原因:

1。 文件类型错误 xocde无法分辨除要编译的文件是objc 还是 objcpp (解决方法见上)

2。 文件未包含在target中 (解决方法见上)

3。源代码文件中使用的framework未包含在程序中 ,在target名称上右键getinfo -》 general -》linked libraries -》+号添加 。或在Frameworks目录上右键 添加exsting frameworks
Share:

xcode object-c c c++混编时出现的错误

error: expected unqualified-id before'@'  ,出现一大堆的错误。

出现这种情况的原因是xcode无法分辨出,要编译的文件类型 是c++ 还是 object-c++ ,所以默认使用object-c

错误情况: object-c代码中使用c++代码

                    或者c++代码中使用object-c 代码

解决情况

如果是在object-c中使用c++代码,则将.m 文件名改为.mm ,另外在文件名上右键-Get info-》将文件类型改为 sourcecode.cpp.objcpp

如果是在c++类中引用object-c代码,则在文件名上右键-Get info-》将文件类型改为 sourcecode.cpp.objcpp
Share:

2010年3月29日星期一

Windows字符串函数

Microsoft C包括宽字符和需要字符串参数的C语言执行时期链接库函数的所有普通版本。不过,Windows复制了其中一部分。例如,下面是Windows定义的一组字符串函数,这些函数用来计算字符串长度、复制字符串、连接字符串和比较字符串:

ILength = lstrlen (pString) ;
       
pString = lstrcpy (pString1, pString2) ;
       
pString = lstrcpyn (pString1, pString2, iCount) ;
       
pString = lstrcat (pString1, pString2) ;
       
iComp = lstrcmp (pString1, pString2) ;
       
iComp = lstrcmpi (pString1, pString2) ;
这些函数与C链接库中对应的函数功能相同。如果定义了UNICODE标识符,那么这些函数将接受宽字符串,否则只接受常规字符串。

 ASCII
 宽字符
 常规
 
参数的变数个数
   
标准版
 sprintf swprintf _stprintf
 
最大长度版
 _snprintf _snwprintf _sntprintf
 
Windows版
 wsprintfA wsprintfW wsprintf
 
参数数组的指针
   
标准版
 vsprintf vswprintf _vstprintf
 
最大长度版
 _vsnprintf _vsnwprintf _vsntprintf
 
Windows版
 wvsprintfA wvsprintfW wvsprintf
 

成为符合ANSI和Unicode的应用程序

即使你不打算立即使用U n i c o d e ,最好也应该着手将你的应用程序转换成符合U n i c o d e 的应用程序。下面是应该遵循的一些基本原则:

• 将文本串视为字符数组,而不是c h a r s 数组或字节数组。
• 将通用数据类型(如T C H A R 和P T S T R )用于文本字符和字符串。
• 将显式数据类型(如B Y T E 和P B Y T E )用于字节、字节指针和数据缓存。
• 将T E X T 宏用于原义字符和字符串。
• 执行全局性替换(例如用P T S T R 替换P S T R )。
• 修改字符串运算问题。例如函数通常希望你在字符中传递一个缓存的大小,而不是字节。


这意味着你不应该传递s i z e o f ( s z B u ff e r ) ,而应该传递(s i z e o f ( s z B u ff e r ) / s i z e o f ( T C H A R )。另外,如果需要为字符串分配一个内存块,并且拥有该字符串中的字符数目,那么请记住要按字节来分配内存。这就是说,应该调用malloc(nCharacters *sizeof(TCHAR)),而不是调用m a l l o c( n C h a r a c t e r s )。在上面所说的所有原则中,这是最难记住的一条原则,如果操作错误,编译器将不发出任何警告。
Share: