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变量

自定义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

iso 4 中textFieldShouldBeginEditing的问题

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

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

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];

}

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会在新线程中被执行。

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];

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保存到磁盘文件)

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]);

}

iPhone-屏幕截取

-(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];

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