iOS代码工具箱

 

#import <Foundation/Foundation.h>

@interface NSCalendar (equalWithGranularity)

- (BOOL)isDate:(NSDate *)date1 equalToDate:(NSDate *)date2 withGranularity:(NSCalendarUnit)granularity;

@end

#import "NSCalendar+equalWithGranularity.h"

@implementation NSCalendar (equalWithGranularity)

 

- (BOOL)isDate:(NSDate *)date1 equalToDate:(NSDate *)date2 withGranularity:(NSCalendarUnit)granularity {

    if ([date1 isEqualToDate:date2]) {

        return YES;

    }

   

    int componentFlags = [self componentFlagsWithGranularity:granularity];

   

    date1 = [self dateFromDate:date1 withComponentFlags:componentFlags];

    date2 = [self dateFromDate:date2 withComponentFlags:componentFlags];

   

    return [date1 isEqualToDate:date2];

}

 

- (int)componentFlagsWithGranularity:(NSCalendarUnit)granularity

{

    int componentFlags = 0;

   

    for (int i = 1<<1 ; i <= granularity ; i = i<<1) {

        componentFlags = componentFlags | i;

    }

   

    return componentFlags;

}

 

- (NSDate *)dateFromDate:(NSDate *)date withComponentFlags:(int)componentFlags {

    NSDateComponents *components = [self components:componentFlags fromDate:date];

   

    return [self dateFromComponents:components];

}

@end

  • CGRect rect = { CGPointZero, image.size };
  • 光照效果+杂色效果

 

杂色图片附件 

  • 使用解固XIB文件得到的视图,初始化方法为initWithCoder:;使用代码创建的视图,初始化方法为initWithFrame:。
  • Podfile文件配置
  • 自定义模态跳转动画
  • 当某一线程上正在运行一个任务,接着在没有取消该线程的情况下,又启动了一个执行同样操作任务的线程。当最初的线程执行完任务后,执行清理工作,并将清理工作的运行环境关闭。而新开的线程上的操作执行完以后也执行一次清理工作,但此时执行清理的运行环境已经被关闭,致使app奔溃。所以在开启一个同样操作的新线程的时,要取消之前的线程。这在不断点击同一个事件触发按钮时尤为明显。

           当使用NSOperation类进行网络请求(AFNetworking的网络请求对象就是基于NSOperation),如果用户离开某个请求还没有完成的界面,除了将NSOpeation取消,还需要在NSOpeation块内时刻监测NSOpeation类的isCancelled属性的变化。当块内的某个操作比较耗时,即使你取消了操作,但可能此时NSOperation已经获取到了结果,只是在处理得到的结果,因为取消并不能让NSOpeation块内的代码停下来。所以对于耗时的操作,在操作前要检测NSOpeation是否被取消。

          当使用MBProgressHUD,对hud设置当前页面的控制器为hud代理。记住:当退出当前控制器视图时,要将hud的代理置为nil,防止出现使用hide:afterDelay:方法后,hud延迟隐藏之后回调已经被释放的代理,而致使ap奔溃。

     代码运行截图:

    

  • 内阴影+外阴影+边框效果

  • CGRectInset与CGRectOffset的区别

      CGRect CGRectInset (
      CGRect rect,
      CGFloat dx,
      CGFloat dy
    ); 
    该结构体的应用是以原rect为中心,再参考dx,dy,进行缩放或者放大。dx,dy为正数缩小,负数则放大。如果缩放后的结果矩形的宽或高存在负值,则返回空矩形。

    CGRect CGRectOffset(
           CGRect rect,
           CGFloat dx,
           CGFloat dy
   );
    
   相对于源矩形原点rect(左上角的点)沿x轴和y轴偏移

  • Quartz常用曲线路径的相关函数:from:http://blog.shoguniphicus.com/2011/05/19/keyframe-animation-ios-cakeyframeanimation-objective-c/

曲线的理论基础是贝塞尔曲线,曲线的定义有四个点:起始点、终止点(也称锚点)以及两个相互分离的中间点。滑动两个中间点,贝塞尔曲线的形状会发生变化。

 <1> 关于CGPathAddQuadCurveToPoint(path, NULL, cx, cy, x, y)。cx、cy为控制点的xy坐标,x、y为结束点。该函数只有一个控制点,当控制点的x坐标处在开始点和结束点的中间,则该条曲线关于中心点y轴对称。

      CGPathAddQuadCurveToPoint函数原理图

示例代码1:

  

                        代码1运行截图

<2>关于CGPathAddCurveToPoint(path, NULL, cx1, cy1, cx2, cy2, x, y);cx1、cy1为控制点1点xy坐标,cx2、cy2为控制点2的xy坐标。x、y为结束点。

          CGPathAddCurveToPoint函数原理图

示例代码2:

                            代码2运行截图

<3>关于void CGPathAddArcToPoint (CGMutablePathRef path,const CGAffineTransform *m, CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2, CGFloat radius)。

该函数想可变的图形路径中追加一条弧线,可能弧线的前面是一条直线。该函数使用了一个三次贝塞尔曲线序列以创建一个弧线。当前点到(x1,y1)的直线以及(x1,y1)到(x2,y2)直线与弧线相切。弧线的开始点和结束点被分别定位在第一条与第二条切线上。弧线的开始点和结束点也被成为线段的切点。如果当前的点和第一个弧线的切点不相等,quartz就追加一条从当前点到第一个弧线切点的直线段。弧线的结束点变成了新路径的当前点。在路径中绘制弧线的另外方式,可见CGPathAddArc参数。

 

              CGPathAddArcToPoint函数原理图

示例代码3:

              代码3运行截图

<4>关于void CGPathAddArc ( CGMutablePathRef path,const CGAffineTransform *m, CGFloat x, CGFloat y, CGFloat radius, CGFloat startAngle, CGFloat endAngle, bool clockwise)。x和y表示圆心的xy坐标。radius表示半径。startAngle和endAngle表示开始和结束角度。clockwise如果为YES,表示从开始角度到结束角度之间的弧线以顺时针方向,也即为从左到右,从上到下。如果为NO表示从左到右,从下到上。如原理图所示。具体关于该函数的数学原理,请参见:http://blog.csdn.net/zhanglei5415/article/details/8147833  中”创建弧线-数学问题“一节。

 

      CGPathAddArc函数参数表征的具体元素

                    CGPathAddArc函数原理图

示例代码4:

 代码4运行截图

  • 绘制带有阴影的圆
  • 不规则阴影代码:

   from:http://nachbaur.com/blog/fun-shadow-effects-using-custom-calayer-shadowpaths

    代码运行截图:

不规则阴影路径的绘制主要使用shadowPath属性,使用阴影路径可以大幅提升阴影绘制的性能。 阴影路径告诉UIKit将路径内的区域设置为不透明,这减少了渲染引擎的大部分工作。

  • CABasicAnimation中animationKeyPath的属性值。

   from:http://www.cnblogs.com/pengyingh/articles/2379631.html

  CABasicAnimation 为图层属性提供了基本的单关键帧动画功能。创建CABasicAnimation实例的一般方法是通过继承的类方法animationWithKeyPath:,并给出在渲染树中生成的动画的关键路径属性。 

   可以通过animationWithKeyPath键值对的方式来改变动画。animationWithKeyPath的值包括针对一般属性变化和几何变化两类。几何变换包括平移、旋转、缩放。

如下表所示为几何变换keypath:

另:CAAnimation的delegate方法:

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {

  NSLog(@"animation stop");

}

- (void)animationDidStart:(CAAnimation *)theAnimation {

  NSLog(@"animation start");

}

 一般的属性变化包括以下几个keypath属性:
margin
zPosition
backgroundColor
cornerRadius
borderWidth
bounds
contents
contentsRect
cornerRadius
frame
hidden
mask
masksToBounds
opacity
position
shadowColor
shadowOffset
shadowOpacity
shadowRadius
简单图层属性变化动画
  • CATransform3D制作3D动画效果 

                

                  初始状态                                                 点击后状态

  • 路径动画示例代码(商品落入购物车)

from:http://stackoverflow.com/questions/1142727/how-can-i-animate-the-movement-of-a-view-or-image-along-a-curved-path

  • CATransition 类实现了图层的过度动画效果。可以通过从预定义的过渡集合中选择过渡效果,或是提供自定义的CIFilter实例。

     from:http://www.devdiv.com/home.php?mod=space&uid=8639&do=blog&id=4143

     其中有些过渡类型没有出现在Common transition types documentation中。这可能会导致应用被apple store拒绝,但仅仅是可能,因为至今还没有明确的文档或资料说使用Core Animation的无文档的过渡效果API会被apple store拒绝。在iphonedevsdk上也讨论过该问题,其中一位回答者谈到:“I asked Apple's engineers about this specific issue. They said that officially, undocumented transition effects are just like any other undocumented API feature, and are not allowed.However, their automated tools are not set up to detect using undocumented transitions like they are using undocumented methods, so you may get away with it, and you may not. It's a gamble.”。

代码部分:

  • [UIView transitionFromView] 视图间的切换

      from:http://stackoverflow.com/questions/3602434/transition-behavior-using-transitionfromview-and-transitionwithview

  • 仿射变换的回退 

CGAffineTransform inverse = CGAffineTransformInvert(CGAffineTransformMakeTranslation(5.0, 5.0));

  • 多个仿射变换的拼接

CGAffineTransform transform = CGAffineTransformConcat(CGAffineTransformMakeScale(1, 1), CGAffineTransformMakeTranslation(-50, -50));

  • 判断视图显示或消失的原因

      偶尔我们需要了解视图显示和消失的原因,比如说,你可能想知道一个视图的显示是因为它被加入到一个容器中还是因为其他遮蔽它的内容被移除才致使它被显示。一个常见的例子是当使用导航控制器,你的内容控制器视图可能是因为视图控制器被压入导航控制器栈中而被显示,也有可能是因为在它上面的控制器从栈中被移除致使其显示。

      UIViewController类提供一组可以调用以了解视图的显示状态变化的原因,下表是对这些方法的描述与用法。这些方法可以在viewWillAppear:viewDidAppear:,viewWillDisapper:viewDidDisppaer:方法中使用。

方法名  

用法

isMovingFromParentViewController    

viewWillDisappaer:与viewDidDisapper:方法中调用这个方法,用以了解视图控制器的视图被隐藏是因为视图控制器从它的容器控制器中被移除。  

isMovingToParentViewController  

viewWillAppear:和viewDidAppear方法中调用,用以了解视图控制器的显示是因为视图控制器被加入到容器视图控制器中。

isBeingPresented  

viewWillAppaer:与viewDidApper:方法中调用这个方法,用以了解视图控制器的视图被显示是因为被另外的控制器呈现,如模态呈现

isBeingDismissed  

在viewWillDisappear:和viewDidDisappear方法中调用,用以了解视图控制器的的隐藏是因为控制器被dismissed

下载地址:http://dl.vmall.com/c0k19fs478

  • UITableview滚动触发事件

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;

{

[self.searchBox resignFirstResponder];

}

  • 去除UITableview多余的空行横线 

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {

// This will create a "invisible" footer

return 0.01f;

}

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section

{

return [UIView new];

}

  • UIPickerView添加图标行

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row

forComponent:(NSInteger)component reusingView:(UIView *)view {

UILabel *firstLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 0, 60, 32)];

firstLabel.text = [array1 objectAtIndex:row];

firstLabel.textAlignment = UITextAlignmentLeft;

firstLabel.backgroundColor = [UIColor clearColor];

UILabel *secondLabel = [[UILabel alloc] initWithFrame:CGRectMake(165, 0, 60, 32)];

secondLabel.text = [array2 objectAtIndex:row];

secondLabel.textAlignment = UITextAlignmentLeft;

secondLabel.backgroundColor = [UIColor clearColor];

UIImage *img = [UIImage imageNamed:[NSString stringWithFormat:@"%@.png",[countries objectAtIndex:row]]];

UIImageView *icon = [[UIImageView alloc] initWithImage:img];

temp.frame = CGRectMake(170, 0, 30, 30);

UIView *tmpView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 290, 32)] autorelease];

[tmpView insertSubview:icon atIndex:0];

[tmpView insertSubview:firstLabel atIndex:0];

[tmpView insertSubview:secondLabel atIndex:0];

[tmpView setUserInteractionEnabled:NO];

[tmpView setTag:row];

[channelLabel release];

[temp release];

return tmpView;

}

from:http://stackoverflow.com/questions/10128068/uipickerview-showing-images-and-strings

  • iOS中使用自定义字体

Here’s the updated details of how to use custom fonts in iPhone. This is only available for SDK 4.0 and above.

  1. Add your custom font files into your project using XCode as resources.
  2. Add a key to your info.plist file called “Fonts provided by application” ( Used to be called UIAppFonts).
  3. It’s an array key.
  4. For each font you have, enter the full name of your font file (including the extension).
  5. Save info.plist.
  6. Now in your application you can simply call [UIFont fontWithName:@"CustomFontName" size:12] to get the custom font to use with your UILabels and UITextView.
  7. “CustomFontName” is not the font’s file name. It is the font name registered in the operating system. For example, if you try to use “Bauhaus Medium BT.ttf”, the “CustomFontName” should be “Bauhaus Md BT”, no extension “.ttf” is needed. You need to install the font in your system to find out what name it is. Some fonts have 2 names, you may need FontForge to find out and try which one works.
  8. So far I found out that both ttf and otf format work out of the box. I haven’t tested other font formats yet.

*Points 1-6 credit to http://blog.beefyapps.com/

  • iOS启动画面设计的若干建议

 try a very simple logo and a solid background. Its a loading screen that is only seen for a few seconds and doesn't need to be fansy., make your splash screen be something that will compress well as a png file. Two things happen, first the pixels are passed through a filter function to take advantage of the fact that pixel near each other will have similar values, then they are compressed with the deflate algorithm (same as used by gzip or zlib).

So some things that can help take advantage of that.
1) Avoid photos. They have a lot of noise and detail in them which doesn't compress well as png.
2) If possible, use very few colors. A solid color background with some text on it is going to compress very small. ~100kb for a 1024x768.
3) Similar to #2, reduce your colors. You don't *really* need a 24bit png file to display on a (probably?) 18-21 bit LCD. Use the photoshop "posterize" command. See if 64 or 32 levels looks ok for your art.
4) Avoid dithering if possible. Dithering adds a bunch of randomness to the data that compresses poorly.
5) Less detail means more repetition that the can be compressed.
6) Stick with simple linear gradients if possible.

  • 删除.svn文件脚本

find ./ -name .svn -exec rm -rf {} \;

  •  Mac OS 显示/关闭显示被隐藏的文件终端命令:

1.显示

defaults write com.apple.finder AppleShowAllFiles -bool true

KillAll Finder

2.关闭显示

defaults write com.apple.finder AppleShowAllFiles -bool false

KillAll Finder

  • 关于时间的若干操作 from:http://blog.csdn.net/yangbo_hbzjk/article/details/7625276

1 // 当前时间创建NSDate

NSDate *myDate = [NSDate date];

NSLog(@"myDate = %@",myDate);

2 //从现在开始的24小时

NSTimeInterval secondsPerDay = 24*60*60;

NSDate *tomorrow = [NSDate dateWithTimeIntervalSinceNow:secondsPerDay];

NSLog(@"myDate = %@",tomorrow);

3//根据已有日期创建日期

NSTimeInterval secondsPerDay1 = 24*60*60;

NSDate *now = [NSDate date];

NSDate *yesterDay = [now addTimeInterval:-secondsPerDay1];

NSLog(@"yesterDay = %@",yesterDay);

4//比较日期

BOOL sameDate = [now isEqualToDate:yesterDay];

NSLog(@"sameDate = %lu",sameDate);

4.1//获取较早的日期

NSDate *earlierDate = [yesterDay earlierDate:now];

NSLog(@"earlierDate = %@",earlierDate);

4.2//较晚的日期

NSDate *laterDate = [yesterDay laterDate:now];

NSLog(@"laterDate = %@",laterDate);

//两个日期之间相隔多少秒

NSTimeInterval secondsBetweenDates= [yesterDay timeIntervalSinceDate:now];

NSLog(@"secondsBetweenDates= %lf",secondsBetweenDates);

//通过NSCALENDAR类来创建日期

NSDateComponents *comp = [[NSDateComponentsalloc]init];

[comp setMonth:06];

[comp setDay:01];

[comp setYear:2001];

NSCalendar *myCal = [[NSCalendaralloc]initWithCalendarIdentifier:NSGregorianCalendar];

NSDate *myDate1 = [myCal dateFromComponents:comp];

NSLog(@"myDate1 = %@",myDate1);

//从已有日期获取日期

unsigned units = NSMonthCalendarUnit|NSDayCalendarUnit|NSYearCalendarUnit;

NSDateComponents *comp1 = [myCal components:units fromDate:now];

NSInteger month = [comp1 month];

NSInteger year = [comp1 year];

NSInteger day = [comp1 day];

//NSDateFormatter实现日期的输出

NSDateFormatter *formatter = [[NSDateFormatteralloc]init];

[formatter setDateStyle:NSDateFormatterFullStyle];//直接输出的话是机器码

//或者是手动设置样式[formatter setDateFormat:@"yyyy-mm-dd"];

NSString *string = [formatter stringFromDate:now];

NSLog(@"string = %@",string);

NSLog(@"formater = %@",formatter);

question: Given a NSDate * startDate and endDate and a NSManagedObjectContext * moc:

NSPredicate*predicate =[NSPredicate predicateWithFormat:@"(date >= %@) AND (date <= %@)", startDate, endDate];

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

[request setEntity:[NSEntityDescription entityForName:@"EntityName" inManagedObjectContext:moc]];

[request setPredicate:predicate];NSError*error = nil;

NSArray*results =[moc executeFetchRequest:request error:&error];

  • 添加调试条件

objc_exception_throw

  • NSMutableSet操作

- (void)unionSet:(NSSet *)otherSet; // 求并集

- (void)minusSet:(NSSet *)otherSet; // 求差集

- (void)intersectSet:(NSSet *)otherSet; // 求交集

· Block作为形参

语法:(<返回类型> (^)(参数列表…))<块名>

(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON))success

  • Block类型重定义

语法:typedef <返回类型> (^类型名)(参数列表);

typedef void (^MBProgressHUDCompletionBlock)();

typedef void (^SuccessBlock)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON);

  • 放置在UIScrollView上的UIImageView响应点击事件

UIImageView* myImageView;

myImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"ic_playvideo.png"]];

myImageView.userInteractionEnabled = YES;

UITapGestureRecognizer *pgr = [[UITapGestureRecognizer alloc] initWithTarget:self  action:@selector(handleTapEvent:)];

[myImageView addGestureRecognizer:pgr];

- (void) handleTapEvent: (id)sender {

UIImageView* touchedImageView = (UIImageView*)((UITapGestureRecognizer *)sender).view;

}

  • 移除视图的所有子视图

[[myView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];

  • 两个日期相距的秒数

NSDate *lastDate = [NSDate date];

NSDate *todaysDate = [NSDate date];

NSTimeInterval lastDiff = [lastDate timeIntervalSinceNow];

NSTimeInterval todaysDiff = [todaysDate timeIntervalSinceNow];

int intervalSecond = lastDiff - todaysDiff;

  • 限制UITextView字数

  - (BOOL)isAcceptableTextLength:(NSUInteger)length {

    return length <= kWordLimit;

  }

  - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)string {  

    return [self isAcceptableTextLength:textView.text.length + string.length - range.length];

  }

 

  限制UITextField字数

- (BOOL)textField:(UITextField *) textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

NSUInteger oldLength = [textField.text length];

NSUInteger replacementLength = [string length];

NSUInteger rangeLength = range.length;

NSUInteger newLength = oldLength - rangeLength + replacementLength;

BOOL returnKey = [string rangeOfString: @"\n"].location != NSNotFound;

return newLength <= kWordLimit || returnKey;

}

  • 方法响应检测执行

 if ([self.delegate respondsToSelector:@selector(dismissPopoverView:)]) {

[_delegate performSelector:@selector(dismissPopoverView:) withObject:sender];

}

  •  protocol声明规范

@class PlayerDetailsViewController;

@protocol PlayerDetailsViewControllerDelegate <NSObject>

- (void)playerDetailsViewControllerDidCancel:(PlayerDetailsViewController *)controller;

- (void)playerDetailsViewControllerDidSave:(PlayerDetailsViewController *)controller;

@end

@protocol PlayerDetailsViewControllerDelegate <NSObject>

- (void)playerDetailsViewControllerDidCancel:(PlayerDetailsViewController *)controller;

- (void)playerDetailsViewController:(PlayerDetailsViewController *)controller didAddPlayer:(Player *)player;

@end

  • UIBarButtonItem添加间隙

UIBarButtonItem *fixed;

fixed = [[UIBarButtonItem alloc]

initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];

fixed.width = 8;

  • 对数组排序的三种方法、

1. 使用比较方法

- (NSComparisonResult)compare:(Person *)otherObject {

return [self.birthDate compare:otherObject.birthDate];

}

NSArray *sortedArray;

sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(compare:)];

2. 使用NSSortDescriptor(最佳)

NSSortDescriptor *sortDescriptor;

sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"birthDate"

ascending:YES] autorelease];

NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];

NSArray *sortedArray;

sortedArray = [drinkDetails sortedArrayUsingDescriptors:sortDescriptors];

3. 使用block ()

NSArray *sortedArray;

sortedArray = [drinkDetails sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {

  NSDate *first = [(Person*)a birthDate];  

  NSDate *second = [(Person*)b birthDate];

  return [first compare:second];

}];

  • NSSet排序

NSArray *sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]];

NSArray *sortedRecipes = [[recipes allObjects] sortedArrayUsingDescriptors:sortDescriptors];

  • NSSet转化为NSMutableArray

NSMutableArray *array = [NSMutableArray arrayWithArray:[set allObjects]];

NSMutableArray *array = [[set allObjects] mutableCopy];

  • 消除NSString首尾空格

- (NSString *)stringByTrimmingLeadingCharactersInSet:(NSCharacterSet *)characterSet {

  NSRange rangeOfFirstWantedCharacter = [self rangeOfCharacterFromSet:[characterSet invertedSet]];

  if (rangeOfFirstWantedCharacter.location == NSNotFound) {

    return @"";

  }

  return [self substringFromIndex:rangeOfFirstWantedCharacter.location];

}

- (NSString *)stringByTrimmingLeadingWhitespaceAndNewlineCharacters {

  return [self stringByTrimmingLeadingCharactersInSet:

  [NSCharacterSet whitespaceAndNewlineCharacterSet]];

}

- (NSString *)stringByTrimmingTrailingCharactersInSet:(NSCharacterSet *)characterSet {

  NSRange rangeOfLastWantedCharacter = [self rangeOfCharacterFromSet:[characterSet invertedSet]

  options:NSBackwardsSearch];

  if (rangeOfLastWantedCharacter.location == NSNotFound) {

    return @"";

  }

  return [self substringToIndex:rangeOfLastWantedCharacter.location+1]; // non-inclusive

}

- (NSString *)stringByTrimmingTrailingWhitespaceAndNewlineCharacters {

  return [self stringByTrimmingTrailingCharactersInSet:

  [NSCharacterSet whitespaceAndNewlineCharacterSet]];

 

  • nil是一个对象指针为空,Nil是一个类指针为空,NULL是基本数据类型为空

id aValue = [arrayWithNull objectAtIndex:0];

if (aValue == nil) {

  NSLog(@"equals nil");

  } else if (aValue == [NSNull null]) {

    NSLog(@"equals NSNull instance");

    if ([aValue isEqual:nil]) {

      NSLog(@"isEqual:nil");

  }

}

  • 添加DEBUG预处理标记

·         获得一个类的属性列表 from: http://stackoverflow.com/questions/754824/get-an-object-attributes-list-in-objective-c

- (void)myMethod {

  unsigned int outCount, i;

  objc_property_t *properties = class_copyPropertyList([self class], &outCount);

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

  objc_property_t property = properties[i];

  const char *propName = property_getName(property);

  if(propName) {

    const char *propType = getPropertyType(property);

    NSString *propertyName = [NSString stringWithCString:propName];

    NSString *propertyType = [NSString stringWithCString:propType];

...

  }

}

free(properties);

}

static const char *getPropertyType(objc_property_t property) {

  const char *attributes = property_getAttributes(property);

  char buffer[1 + strlen(attributes)];

  strcpy(buffer, attributes);

  char *state = buffer, *attribute;

  while ((attribute = strsep(&state, ",")) != NULL) {  

    if (attribute[0] == 'T') {

     return (const char *)[[NSData dataWithBytes:(attribute + 3) length:strlen(attribute) - 4] bytes];   

   }

}

return "@";

}

·         URL中文编码与解码

iOS app开发中,如果需要对url中的中文和特殊字符进行url编码,一般有两种方法:

1. 使用NSString实现encode

NSString* sURL = [string stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

实现decode

NSString* sURL = [string stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

2.使用CFStringRef实现encode

指定需要编码的字符

NSString* sURL = (NSString*)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)input, NULL, (CFStringRef)@"!*'();:@&=+$,/?%#[]", kCFStringEncodingUTF8);

如果仅仅只需要编码中文

NSString* sURL = (NSString*)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)input, NULL, NULL, kCFStringEncodingUTF8);

实现decode:

NSMutableString* inputStr = [NSMutableString stringWithString:input];

[inputStr replaceOccurrencesOfString:@"+" withString:@" " options:NSLiteralSearch range:NSMakeRange(0, [inputStr length])];

NSString* sURl = [inputStr stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

·         获得一个类的实例变量列表

unsigned int varCount;

Ivar *vars = class_copyIvarList([MyClass class], &varCount);

for (int i = 0; i < varCount; i++) {

  Ivar var = vars[i];

  const char* name = ivar_getName(var);

  const char* typeEncoding = ivar_getTypeEncoding(var);

  // do what you wish with the name and type here

}

free(vars);

from: http://stackoverflow.com/questions/1213901/how-do-i-list-all-instance-variables-of-a-class-in-objective-c

·         连接NSSet元素,转化为NSString类型 

NSSet*set = [NSSet setWithObjects:@"String 1",@"String 2",@"String 3", nil];

NSString* string = [[set allObjects] componentsJoinedByString:@" "];

·         Option+command拖动模拟器文件夹到桌面,创建快捷方式

·         在何处移除观察者

The generic answer would be "as soon as you no longer need the notifications". This is obviously not a satisfying answer.

I'd recommend, that you add a call [notificationCenter removeObserver: self] in methoddealloc of those classes, which you intend to use as observers, as it is the last chance to unregister an observer cleanly. This will, however, only protect you against crashes due to the notification center notifying dead objects. It cannot protect your code against receiving notifications, when your objects are not yet/no longer in a state in which they can properly handle the notification. For this... See above.

-(void) dealloc {

[[NSNotificationCenter defaultCenter] removeObserver:self];

[super dealloc];

}

from: http://stackoverflow.com/questions/6469209/objective-c-where-to-remove-observer-for-nsnotification

如果出现在dealloc中移除通知,却发现dealloc没有调用,导致发一次通知会调用同样一段代码多次。这时候就要注意,因为很明显当前类没有被释放。如果你选择将添加通知放在viewWillAppear中,移除通知放在viewWillDisappear中,虽然暂时可以将多次调用解决掉。但是类没有被释放的问题还是没有解决。而导致类没有被释放的原因很可能就是当前类虽然从navigationController中弹出了或者从父控制器dismiss了,但是还存在对当前类的strong引用,比如代理之类的引用。对于ARC来说,默认是strong引用。此时你只需要在其他类中将对当前类的引用改成weak就可以让dealloc重新被调用了。有用的讨论地址:http://stackoverflow.com/questions/8727316/arc-uinavigationcontroller-stack-not-getting-deallocated-when-presented-as-modal

·                          添加通知

- (void)viewDidAppear:(BOOL)animated {

  [super viewDidAppear:animated];

 

  [self checkSyncStatus];

 

  [[NSNotificationCenter defaultCenter] addObserverForName:@"observerKey" object:nil queue:nil usingBlock:^(NSNotification *note) {

  [self loadRecordsFromCoreData];

  [self.tableView reloadData];

  }];

  [[SDSyncEngine sharedEngine] addObserver:self forKeyPath:@"observerKey" options:NSKeyValueObservingOptionNew context:nil];

}

 

- (void)viewDidDisappear:(BOOL)animated {

  [super viewDidDisappear:animated];

  [[NSNotificationCenter defaultCenter] removeObserver:self name:@"SDSyncEngineSyncCompleted" object:nil];

  [[SDSyncEngine sharedEngine] removeObserver:self forKeyPath:@"syncInProgress"];

}

(IBAction)refreshButtonTouched:(id)sender {

  [[SDSyncEngine sharedEngine] startSync];

}

 

- (void)checkSyncStatus {

  if ([[SDSyncEngine sharedEngine] syncInProgress]) {

    [self replaceRefreshButtonWithActivityIndicator];

  } else {

    [self removeActivityIndicatorFromRefreshButton];

  }

}

 

- (void)replaceRefreshButtonWithActivityIndicator {

  UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 25, 25)];

  [activityIndicator setAutoresizingMask:(UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin)];

  [activityIndicator startAnimating];

  UIBarButtonItem *activityItem = [[UIBarButtonItem alloc] initWithCustomView:activityIndicator];

  self.navigationItem.leftBarButtonItem = activityItem;

}

 

- (void)removeActivityIndicatorFromRefreshButton {

  self.navigationItem.leftBarButtonItem = self.refreshButton;

}

 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {

  if ([keyPath isEqualToString:@"observerKey"]) {

    [self checkSyncStatus];

  }

}

·                          获取字符串中的数据

        做法1

NSString *logString = @"user logged (3 attempts)";

// stringByTrimmingCharactersInSet选取包含在指定字符集中的字符串,invertedSet方法用来获取所有非数字的字符集

 

NSString *digits = [logString stringByTrimmingCharactersInSet: [[NSCharacterSet decimalDigitCharacterSet] invertedSet]]; NSLog(@"Attempts: %i", [digits intValue]);

       输出:Attempts: 3

       做法2

// 源字符串,观察该字符串,会发现该字符串的分隔符包括分号和逗号,并且一段英文字符和三段数字分为一组,共分四组

// 我们的工作就是取出由分号和逗号分割的数据

NSString *sourceString = @"Los Angeles;8.25;0.580561574;1,Tokyo;1.9;0.643872234;1;Honolulu,0;0;0;Toronto;7.9;5.3322;3;";

// 创建一个行扫描器

NSScanner *myScanner = [NSScanner scannerWithString:sourceString];

NSString *stringValue;

float theRevenue;

float thePercent;

int theRank;

// 设置一个何时停止扫描的字符集,该字符集用于扫描器向前扫描时停止扫描的条件

NSCharacterSet *stopSet;

stopSet = [NSCharacterSet characterSetWithCharactersInString:@";,"];

// 判断扫描器是否已经扫描到字符串末尾,到末尾返回YES

while ([myScanner isAtEnd] == NO) {

// 扫描器向前扫描源字符串,直到遇到stopSet包含的字符串位置,并将之前扫描到的字符串放入stringValue

// 与之类似方法有scanUpToString: intoString:

if ( [myScanner scanUpToCharactersFromSet:stopSet intoString:&stringValue] ) {

NSLog (@"%@",stringValue);

}

// 跳过分号或者逗号字符串,也可以使用scanCharactersFromSet: intoString方法

if([myScanner scanString:@";" intoString:NULL] || [myScanner scanString:@"," intoString:NULL]);

// 获取浮点数

if([myScanner scanFloat:&theRevenue])

NSLog(@"%lf",theRevenue);

if([myScanner scanString:@";" intoString:NULL] || [myScanner scanString:@"," intoString:NULL]);

if([myScanner scanFloat:&thePercent])

NSLog(@"%lf",thePercent);

if([myScanner scanString:@";" intoString:NULL] || [myScanner scanString:@"," intoString:NULL]);

if([myScanner scanInt:&theRank])

NSLog(@"%i",theRank);

if([myScanner scanString:@";" intoString:NULL] || [myScanner scanString:@"," intoString:NULL]);

}

·               获取视图的父视图所对应的控制器

- (UIViewController*)viewControllerOfSuperView: (UIView*) subView {

for (UIView* next = [subView superview]; next; next = next.superview){

  UIResponder* nextResponder = [next nextResponder];

  if ([nextResponder isKindOfClass:[UIViewController class]]) {

      return (UIViewController*)nextResponder;

   }

}

  return nil;

}

·                       异步多任务完成后,执行指定操作

dispatch_group_t group = dispatch_group_create();

MyCoreDataObject *coreDataObject;

dispatch_group_enter(group);

AFHTTPRequestOperation *operation1 = [[AFHTTPRequestOperation alloc] initWithRequest:request1];

[operation1 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

coreDataObject.attribute1 = responseObject;

sleep(5);

dispatch_group_leave(group);

}];

[operation1 start];

dispatch_group_enter(group);

AFHTTPRequestOperation *operation2 = [[AFHTTPRequestOperation alloc] initWithRequest:request1];

[operation2 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

coreDataObject.attribute2 = responseObject;

sleep(10);

dispatch_group_leave(group);

}];

[operation2 start];

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

dispatch_release(group);

[context save:nil];

·         数组过滤查找

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"type == %@", @"standard"];

NSArray *filteredArray = [myArray filteredArrayUsingPredicate:predicate];

id firstFoundObject = nil;

if ([filteredArray count] > 0) {

  firstFoundObject = [filteredArray objectAtIndex:0];

}

·        CAScrollLayer的使用

-(void) setupLayers{

  CALayer* mainLayer = self.layer;

  CGFloat midX = CGRectGetMidX( mainLayer.frame );

  CGFloat midY = CGRectGetMidY( mainLayer.frame );

  CAScrollLayer* contentContainer = [CAScrollLayer layer];

  contentContainer.bounds = mainLayer.bounds;

  currentX=contentContainer.bounds.origin.x;

  contentContainer.anchorPoint = CGPointMake(0.5,0.5);

  contentContainer.position = CGPointMake( midX, midY );

  [self.layer addSublayer:contentContainer];

  self.bookRootLayer = contentContainer;

  contentContainer.name = @"scrollLayer";

  contentContainer.scrollMode = kCAScrollHorizontally;

  for (int i=0;i<[self.booksArray count];i++){

    CALayer *singleLayer=[CALayer layer];

    //homebrew shadow

    CALayer *shadowLayer=[CALayer layer];

    shadowLayer.contents=(id)[UIImage imageNamed:@"bookshadow.png"].CGImage;

    shadowLayer.frame=CGRectMake(i*100, (self.frame.size.height-118), 91, 118);

    shadowLayer.name=[NSString stringWithFormat:@"shadow-%d",i];

    [self.bookRootLayer addSublayer:shadowLayer];

    NSDictionary *singleBook=[self.booksArray objectAtIndex:i];

   [singleLayer setContents:(id)[(UIImage*)[singleBook objectForKey:@"imgdata"] CGImage]];

   singleLayer.frame=CGRectMake(i*100+4, (self.frame.size.height-115), 82, 110);

   singleLayer.name=[NSString stringWithFormat:@"layer-%d",i];

   [self.bookRootLayer addSublayer:singleLayer];

    ((CAScrollLayer*)self.bookRootLayer).frame =CGRectMake(0, (self.frame.size.height-110), (i+1)*100, 118);

   }

}

·          移动CAScrollLayer

[self.bookRootLayer scrollToPoint:CGPointMake(100,0)];

·            选取特定Layer

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{

  CGPoint touchLocation = [[touches anyObject] locationInView:self];

  CALayer *hitLayer=[self.bookRootLayer hitTest:touchLocation];

  NSLog(@"LayerName: %@", [hitLayer name]);

}

·          点击UITableViewCell上的UIButton控件,获取指定的NSIndexPath

-(void)OnTouchBtnInCell:(UIButton *)btn

{

  CGPoint point = btn.center;

  point = [table convertPoint:point fromView:btn.superview];

  NSIndexPath* indexpath = [table indexPathForRowAtPoint:point];

  UITableViewCell *cell = [table cellForRowAtIndexPath:indexpath];

}

·         在滚动的时候降低图片画质,提升滚动时的渲染性能

UIImage* highResolution = [UIImage imageNamed:@"CuriousFrog.png"];

NSData* dateFromJPEG = UIImageJPEGRepresentation(highResolution, 0.1f);

UIImage* lowResolution = [UIImage imageWithData:dateFromJPEG];

NSLog(@"%d", [dateFromJPEG length]);

·         NSTimer的用法

1) 预定计时器 & 使用选择器

NSTimer*t =[NSTimer scheduledTimerWithTimeInterval:2.0

                                            target: self

                                          selector:@selector(onTick:)

                                          userInfo: nil

                                               repeats:NO];

·         如果将repeats参数设为NO,定时器将在等待2秒钟之后执行选择器,最后将停止。

·         如果repeatsYES,定时器将立即开始,并且每2秒调用一次选择器。

·         通过调用定时器的实例方法invalidate,并将定时器置为nil。以停止定时器。 

2) 自预定定时器

NSDate*d =[NSDate dateWithTimeIntervalSinceNow:60.0];

NSTimer*t =[[NSTimer alloc] initWithFireDate: d interval:1 target:self selector:@selector(onTick:)userInfo:nil repeats:YES];

NSRunLoop*runner =[NSRunLoop currentRunLoop];

[runner addTimer:t forMode:NSDefaultRunLoopMode];

这将创建一个在指定的日期内开始的定时器(上面例子中的定时器会在1分钟之后开始),并会每秒钟重复一次。

判断针对当前app的定位服务是否开启

[CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorized

·         取点击的位置

CGPoint point1=[self.bookRootLayer convertPoint:touchLocation fromLayer:self.layer];

NSLog(@"click point: %f, %f",point1.x, point1.y);

posted @ 2012-12-17 10:22  士梦  阅读(2641)  评论(2编辑  收藏  举报