[NSOperationQueue mainQueue] //这个是主队列
[NSThread mainThread]; //这个是主线程
他俩是什么关系呢,确切的说队列和线程之间是什么关系呢??
好像有点傻傻分不清😂😂
首先
主线程和主队列都是多线程的一种方式,关于多线程苹果有三种实现方法:
- NSThread
- 2.NSOperation/NSOperationQueue
- 3.GCD
三种方式的抽象程度不同,越后面越容易使用,所以你可以理解为队列是对线程的一个包装,让用户更容易使用,所以队列的底层也是通过线程来实现的
至于主线程和主队列非要说有什么关系的话,根据我上面说的就很清楚了,主队列里的任务一定是在主线程中执行的,就这样而已.
异步和多线程的关系的理解##
异步和多线程并不是一个同等关系,异步是最终目的,多线程只是我们实现异步的一种手段。异步是当一个调用请求发送给被调用者,而调用者不用等待其结果的返回而可以做其它的事情。
1.异步通信的意思是,当A发送完消息之后,不等待B的回应,继续执行之后的程序.在将来的某个时刻,A再来检查是否收到B的回应。
异步就是彼此独立,在等待某事件的过程中继续做自己的事,不需要等待这一事件完成后再工作。2.多线程是程序设计的逻辑层概念,它是进程中并发运行的一段代码。多线程可以实现线程间的切换执行。
3.异步和同步是相对的,同步就是顺序执行,执行完一个再执行下一个,需要等待、协调运行。线程就是实现异步的一个方式。异步是让调用方法的主线程不需要同步等待另一线程的完成,从而可以让主线程干其它的事情。
异步和多线程并不是一个同等关系,异步是最终目的,多线程只是我们实现异步的一种手段。异步是当一个调用请求发送给被调用者,而调用者不用等待其结果的返回而可以做其它的事情。实现异步可以采用多线程技术或则交给另外的进程来处理。
@import VS #import
在xcode 5 下,为了更易于开发,增加了modules和 auto-linking 这两个新特性。用 @import 来增加框架 到项目中比用 #import会更有效. 我们来看看为什么:
"Modules for system frameworks speed build time and provide an alternate means to import APIs from the SDK instead of using the C preprocessor. Modules provide many of the build-time improvements of precompiled headers with less maintenance or need for optimization. They are designed for easy adoption with little or no source changes. Beyond build-time improvements, modules provide a cleaner API model that enables many great features in the tools, such as Auto Linking."
Modules and auto-linking 默认情况下是enabled的。 如果是旧的项目,你可以通过设置"Language - Modules." 来设置Enable Modules 和Link Frameworks Automatically 为Yes。
另外一个使用moudules的好处是你再也不用去链接你的framework到你的项目了。例如,在以前,如果你要使用MapKit这个框架,你要这样做:
- 使用语句 #import <MapKit/MapKit.h> 导入框架
- 去到项目的build phases 设置项,找到MapKit.framework.并加入到Link Binary With Libraries里面。
如果使用modules的话,只需要加入语句 "@import MapKit;" 你就可以开始使用了,根本不需要链接到你的项目。
详细解答
C 指针复习
&x是对x变量取地址,也就是返回的是x的地址。
int i;这里面的说明变量i是一个指针,存的是一个地址。
而printf("%d\n",i);这里面的的作用是返回指针i所指的变量。
&是取地址符号,既取得某一个变量的地址;如:&a
,而 *
是指针运算符(乘号就不说了),可以表示一个变量是指针类型;也可以表示一个指针变量的所指向的存储单元,可以获取某个地址存储的值。
*p就是p所指对象的数值
**1、const **
const :被const修饰符修饰过的变量,真个变量就会变成一个常量。他的值在代码其他部分不能再修改,这对于函数调用时候,防止错误的修改原本不应修改的变量起到很大作用
const char *p
,char const *p
,char * const p
三者共同点是定义了一个char类型 p指针
const char *p
与char const *p
效果一样,都是不允许修改指针指向的地址空间的值,即把值作为常量
而char * const p
则是不允许修改指针自身,不能再指向其他地方,把指针自己当作常量使用,需要注意的是,使用char * const p
定一个常量指针的时候一定记得赋初始值,否则再其他地方就没法赋值了
-
*
前const 值为常量 (const了*p
), -
*
后const 指针为常量 (const 了p
)
2.== 和 = 纠结
BOOL start = status == noErr; //noErr = 0
==是判等运算符,优先级高于 = 赋值运算符,上面表达式先判等再赋值
沙盒文件夹
//Documents, 文档文件夹, 存放重要的文件(用户的配置信息, 存档等), 并且手机连电脑同步时, 会同步此文件夹;文件夹中存的文件夹体积不能过大
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSLog(@"%@", documentsPath);
//YES打印: /Users/laouhn/Library/Developer/CoreSimulator/Devices/97C763A0-424B-4002-8BBF-9D3FD189CFB0/data/Containers/Data/Application/1AF468D6-6A64-49AB-9F84-CD23885CBEDB/Documents
//NO打印: ~/Documents
//Library, 资源文件夹, 存放资源文件(图片, 音频, ship)
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) firstObject];
NSLog(@"%@", libraryPath);
//tmp, 临时文件, 存过度文件(压缩包)
NSLog(@"%@", NSTemporaryDirectory());
//*.app, 应用程序包(文件夹), 存放编译过后的文件(可执行文件, nib)和工程资源, 这个文件夹是只读文件夹
NSLog(@"%@", [[NSBundle mainBundle] bundlePath]);
3.应用间的跳转
跳转App Store下载应用/更新应用
id444934666
为QQ的应用id,换成自己的就行
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"itms-apps://itunes.apple.com/app/id444934666"]];
跳转到App Store评分
[[UIApplication sharedApplication]openURL:[NSURL URLWithString:@"http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?id=APPID&pageNumber=0&sortOrdering=2&type=Purple+Software&mt=8"]];
跳转到手机的设置界面
亲测iOS 11可以跳转到当前APP的授权界面,比链接介绍的方法更好使,但是更改权限后APP会重启,这个是系统行为,能接受就用
NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
if ([[UIApplication sharedApplication] canOpenURL:url]) {
[[UIApplication sharedApplication] openURL:url];
}
# 但是控制台一直会打印
# Application tried to push a nil view controller on target <UINavigationController: 0x13751e4d0>.
4.cell原生分割线 不在底部
场景:在tableView初始化的时候设置了setSeparatorInset:UIEdgeInsetsZero
,重写了cell 的layoutSubViews方法
# 检查发现 漏掉了
[super layoutSubviews];
5.cell原生分割线 不能从头开始
场景:在tableView初始化的时候设置了setSeparatorInset:UIEdgeInsetsZero
,发现用系统的cell 可以从头开始,自定义的cell不能。最终在tableView所属的控制器里面,如下操作才得以解决。
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
if ([cell respondsToSelector:@selector(setSeparatorInset:)]) {
[self.myTable setSeparatorInset:UIEdgeInsetsMake(0, 0, 0, 0)];
}
if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
[cell setLayoutMargins:UIEdgeInsetsZero];
}
}
# 作用貌似不大,可有可无
- (void)viewDidLayoutSubviews{
[super viewDidLayoutSubviews];
if ([self.myTable respondsToSelector:@selector(setSeparatorInset:)]) {
[self.myTable setSeparatorInset:UIEdgeInsetsMake(0, 10, 0, 10)];
} if ([self.myTable respondsToSelector:@selector(setLayoutMargins:)]) {
[self.myTable setLayoutMargins:UIEdgeInsetsZero];
}
}
6.去掉系统返回按钮标题
#要写在 push 之前
UIBarButtonItem *back = [[UIBarButtonItem alloc] init];
back.title = @"";
self.navigationItem.backBarButtonItem = back;
7. iOS9 提醒框
UIAlertController *alertCon = [UIAlertController alertControllerWithTitle:@"重要提示" message:@"删除将无法恢复" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancleAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
NSLog(@"点击确定");
}];
UIAlertAction *otherAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
NSLog(@"点击取消");
}];
[alertCon addAction:cancleAction];
[alertCon addAction:otherAction];
[self presentViewController:alertCon animated:YES completion:nil];
改变 UIAlertController 标题颜色
NSString *title = @"重要提示❗️";
//改变 UIAlertController 标题颜色
NSMutableAttributedString *str = [[NSMutableAttributedString alloc]initWithString:title];
[str addAttribute:NSForegroundColorAttributeName value:[UIColor colorwithHexString:@"#00A0E9"] range:NSMakeRange(0, 6)];
NSString *message = [NSString stringWithFormat:@"删除之后不可恢复\n哈哈哈"];
NSString *cancelButtonTitle = NSLocalizedString(@"确定", nil);
NSString *otherButtonTitle = NSLocalizedString(@"取消", nil);
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
//改变 UIAlertController 按钮颜色
##整个应用层级修改,即修改了整个应用的渲染色,一定要用的话,结束时要改回原来的值
[UIView appearance].tintColor = [UIColor colorwithHexString:@"#00A0E9"];
//点击事件
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:cancelButtonTitle style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
NSLog(@"234");
}];
UIAlertAction *otherAction = [UIAlertAction actionWithTitle:otherButtonTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
}];
[alertController setValue:str forKey:@"attributedTitle"];
// Add the actions.
[alertController addAction:cancelAction];
[alertController addAction:otherAction];
[self presentViewController:alertController animated:YES completion:nil];
8.删除storyBoard 的正确姿势
一般情况下,我们有时候不想用storyboard,但是直接删除的话,Xcode就会报错。那我今天就来讲一下,正确删除storyboard的方法。
第一步,直接将工程中的storyboard直接删除掉,这样你觉得就OK了?你错了,我们还需要第二步。
第二步,找到plist文件,将plist文件中的Main storyboard file base name删除掉,OK
9. _ _ block 使用
BOOL result;
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:cancelButtonTitle style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
result = YES;
}];
error:Variable is not Assignable (missing _block type specifier)
修改为下面
__block BOOL result;
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:cancelButtonTitle style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
result = YES;
}];
10.layoutSubviews何时调用
layoutSubviews在以下情况下会被调用:
- 1、init初始化不会触发layoutSubviews
- 2、addSubview会触发layoutSubviews
- 3、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化
- 4、滚动一个UIScrollView会触发layoutSubviews
- 5、旋转Screen会触发父UIView上的layoutSubviews事件
- 6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件
11.UILabel 加载HTML文本
NSString * htmlString = @"<html><body> Some html string \n <font size=\"13\" color=\"red\">This is some text!</font> </body></html>";
NSAttributedString * attrStr = [[NSAttributedString alloc] initWithData:[htmlString dataUsingEncoding:NSUnicodeStringEncoding] options:@{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType } documentAttributes:nil error:nil];
UILabel * myLabel = [[UILabel alloc] initWithFrame:self.view.bounds];
myLabel.attributedText = attrStr;
[self.view addSubview:myLabel];
第二中,还能显示图片
dataDic = @{@"content":@"<p>他在海外留学八年,回国后只等着接手亿万资产的家族企业,但他却天天开着跑车游手好闲;他决定自力更生,却在社会上屡屡受挫;2010年,他赌气走进大山,睡起草窝;搬进山里后,曾经在朋友面前很有钱的彭然,硬着头皮找朋友借钱;别人的挖苦,成了他前进的动力。80后的彭然,如何让人刮目相看,一年后实现年营业额三百万元?<br/>\r\n\t </p><p>\r\n\t 致富经养殖视频同步解说词:</p><p>\r\n\t这个正在抓鸡的人叫彭然。这里是重庆铜梁县最大的规模养鸡场。凌晨四点抓鸡,早上七点左右,这里的土鸡就会被销往整个铜梁县城和重庆市场。彭然的这家鸡场,一年的营业额达三百万元。而这些,他仅用了一年多就做到了。</p><p>\r\n\t记者:弄得满脸都是泥啊。</p><p>\r\n\t彭然:是,全部都是泥。</p><p>\r\n\t记者:手上也是。</p><p>\r\n\t彭然:对。晚上的时候,鸡是站着不动的,这样抓就好抓。白天到处跑,根本抓不了。</p><p>\r\n\t这个抓起鸡来已经驾轻就熟的年轻人,谁也想不到,他还有另外一个身份。</p><p>\r\n\t朋友朱坤:所谓的富二代,公子哥。</p><p>\r\n\t员工赵晓兰:我还一直都在想这个问题,为什么他妈要他做这个辛苦的活,不相信他家里面有钱。</p><p>\r\n\t彭然是重庆人,家境殷实,资产过亿,在澳大利亚留学八年。养鸡之前,彭然天天过着游手好闲的生活。</p><p>\r\n\t朋友朱坤:玩游戏啊,唱歌啊,酒吧,反正天天这么玩。</p><p>\r\n\t朋友陈毅平:觉得他更像一个小孩,喜欢花时间在游戏上面。</p><p>\r\n\t朋友朱坤:吊儿郎当的,经常比如说做这个事情做做,做到一半,没什么兴趣了,就不做了。</p><p>\r\n\t家里那么有钱,彭然为什么要跑到山里去吃苦,而且还干了养鸡的行当?而更让人觉得蹊跷的是,家里有钱的彭然本应该不为钱愁,可彭然有段时间却只能靠借钱度日,为了二十万元愁得夜不能寐。</p><p>\r\n\t彭然:哪怕我就不要面子,不要脸,也会找朋友借。</p><p>\r\n\t朋友朱坤:第一次,我们认识十几年来第一次向我借钱。</p><p>\r\n\t彭然:就算朋友们怎么说我,怎么挖苦我,先借钱给我再说吧。</p><p>\r\n\t彭然,父母家里资产过亿元,为何还要向朋友借钱?他一个对养鸡一窍不通的门外汉,为什么要跑到山里来吃苦养鸡?而从没做过生意的他,一年后,却硬是靠着自己,实现了年营业额三百万元。</p><p>\r\n\t<img src=\"http://www.nczfj.com/UploadFiles/2012-06/admin/2012689160711.jpg\"/>彭然父母在青海有家大型化工企业,家境殷实。由于父母忙于经营管理,彭然从小学三年级开始就一直上着寄宿学校,17岁时又只身去了澳大利亚留学,一待就是八年,2008年才回到中国。</p><p>\r\n\t母亲张俊秀:在国外那么多年,始终觉得跟我们在一起时间很少,总觉得还是有点亏欠他,我就给他买了一个奥迪TT,每个月给他五千块的工资,经常说,彭然,需不需要钱?</p><p>\r\n\t每月父母经常给的零用钱少则几千,多则上万,彭然的吃穿用度也都由父母的公司实报实销。然而,按照惯例理应接手家族企业的他,却让人大跌眼镜,天天开着跑车,过着游手好闲的生活。</p><p>\r\n\t同学李兴懿:时间完全是颠倒的,白天睡觉,晚上就是耍耍游戏,打牌,反正基本上都是通宵通宵地那种耍。</p><p>\r\n\t母亲张俊秀:我说,我其实很了解你,你是不觉得很空虚?</p><p>\r\n\t彭然:父母就说,你回来又不愿意找工作,那就上班,去自己公司上班。</p><p>\r\n\t彭然确实闲得很空虚,如果去公司上班,时间会过得快一些,还能应付父母,他便欣然同意。但是,朝九晚五的公司规定,对他而言却是一纸空文。</p><p>\r\n\t母亲张俊秀:十点多钟十一点了,有时候穿个睡衣。有时候我都要说他,我说,你还是每天到公司来看一下子。我说,你当个副总,哪个说你不得。</p><p>\r\n\t做母亲的虽然有些看不惯,但张俊秀总觉得亏欠儿子太多。可彭然并不理解父母的心意,除了白天偶尔去下公司,夜生活照常不误。这种生活方式,时间久了,在母亲张俊秀眼里变得格格不入。一天晚上,彭然很晚还没回家,张俊秀忍无可忍便打电话给彭然。</p><p>\r\n\t母亲张俊秀:我说,你出国也有七八年,我也花了起码一百多万。我说,早知道你这样,我一百多万养你吃一辈子你就够了。</p><p>\r\n\t彭然:一听感觉还是挺烦的,我就不做了吧,本来就不喜欢做。</p><p>\r\n\t彭然的回答,让张俊秀火冒三丈。</p><p>\r\n\t母亲张俊秀:你有本事自己养活自己,你不要依靠我。</p><p>\r\n\t彭然:我妈一下就火了,那行,你明天就别来上班了,你的工资全部给你停了。</p><p>\r\n\t母子俩的关系一下子变得僵硬起来,张俊秀痛下决心,果断地停掉了彭然所有的收入。母亲的做法,给了彭然极大的刺激。</p><p>\r\n\t彭然:你想,没钱了怎么办?什么东西都没了。我这个人的性格就是比较不愿意低头。</p><p>\r\n\t母亲把自己说得像寄生虫一般,彭然很不服气,他把这句话记到了心里,赌气要自力更生。</p><p><br/></p>",
@"title":@"如何让人刮目相看,一年后实现年营业额三百万元?",
@"imgUrl":@"http://36.111.32.33:10038/WebServer/images/67128531_3.jpg",
@"date":@"2016-12-09"};
//detailLab
UILabel *detailLab =[UILabel alloc] initWithFrame:CGRectMake(10, NH(imgView)+AutoWHGetHeight(15), width, 10) ]
detailLab.text = dataDic[@"content"];
// NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:detailLab.text];
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithData:[detailLab.text dataUsingEncoding:NSUnicodeStringEncoding] options:@{ NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType} documentAttributes:nil error:nil];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setLineSpacing:10];//调整行间距
// [attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [detailLab.text length])];
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [attributedString length])];
[attributedString addAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kSize16]} range:NSMakeRange(0, [attributedString length])];
detailLab.attributedText = attributedString;
[scrollView addSubview:detailLab];
[detailLab sizeToFit];
scrollView.contentSize = CGSizeMake(SCREEN_WIDTH, NH(detailLab)+30);
[self.view addSubview:scrollView];
12. “Discarding message for event 0 because of too many unprocessed messages” mean?
google翻译:
这是苹果技术支持说的这个(在支付49美元的开发人员技术支持事件后):
这些消息来自核心位置框架。 这些消息的最可能的原因是没有运行循环在创建CLLocationManager的线程上运行。 (这意味着CLLocationManager不是在主线程上创建的)。被丢弃的消息是位置消息:事件0是位置,事件24是例如授权状态更新。 因为消息被丢弃,所以您将看不到调用适当的委托回调。 你设置了地理围栏或其他回调,并且不能很快为其服务吗? 在开始转储事件和记录此消息之前,队列限制显示为10。 此信息尚未公开记录。 我正在与核心位置小组一起改进报告的消息,并看看这是否可以更好地记录。
[[CLLocationManager alloc] init] 没有放在主线程
13.图片压缩处理
14.iOS Security
15. sizeThatFits:
// 1154x434 pixels QQ20170110@2x.png
UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"QQ20170110"]];
imgView.contentMode = UIViewContentModeScaleToFill; //默认显示模式
imgView.frame = CGRectMake(0, 0, 300, 100);
[self.view addSubview:imgView];
CGSize size = [imgView sizeThatFits:CGSizeZero];
imgView.backgroundColor = [UIColor cyanColor];
NSLog(@"%@ -- %@", NSStringFromCGRect(imgView.frame), NSStringFromCGSize(size));
## --
计算的image大小为(1154x433) / 2 = 577x217
16.添加新的SDK工具包
找到路径 Finder -> 应用程序 -> 右键Xcode7.3 -> 显示包内容 -> Contents -> Developer -> Platforms -> iPhoneOS.platform -> DeviceSupport
17.AFN+cache
http://www.cnblogs.com/HJQ2016/p/5968327.html
http://code4app.com/thread-10071-1-1.html
http://www.jianshu.com/p/c695d20d95cb
https://github.com/sky00/SY8APP
https://github.com/yuantiku/YTKNetwork
18.边缘侧滑返回上一级失效
UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:(UIBarButtonItemStyleDone) target:self action:@selector(backIfNeedSave)];
self.navigationItem.leftBarButtonItem = backItem;
上面操作导致左侧边缘侧滑失效
18.TexrField.rightView
推测clearButton也是一个rightView,一旦设置了自定义的,再设置clearButton就不会显示,可以尝试 rightViewRectForBounds: 设置偏移,被遮盖的那个显露出来(未验证)
_textField.rightViewMode = UITextFieldViewModeAlways;
_textField.rightView = [UIView new];
_textField.clearButtonMode = UITextFieldViewModeAlways;
19. coreDate实体属性类型 Integer16,32,64
- Undefined: 默认值,参与编译会报错
- Integer 16: 整数,表示范围 -32768 ~ 32767
- Integer 32: 整数,表示范围 -2147483648 ~ 2147483647
- Integer 64: 整数,表示范围 –9223372036854775808 ~ 9223372036854775807
- Float: 小数,通过MAXFLOAT宏定义来看,最大值用科学计数法表示是 0x1.fffffep+127f
- Double: 小数,小数位比Float更精确,表示范围更大
- String: 字符串,用NSString表示
- Boolean: 布尔值,用NSNumber表示
- Date: 时间,用NSDate表示
- Binary Data: 二进制,用NSData表示
- Transformable: OC对象,用id表示。可以在创建托管对象类文件后,手动改为对应的OC类名。使用的前提是,这个OC对象必须遵守并实现NSCoding协议
在创建时间戳属性时,不放心测试如下
NSDate *date = [NSDate date];
NSTimeInterval interval = [[NSDate date] timeIntervalSince1970];
NSDate *date1970 = [NSDate dateWithTimeIntervalSince1970:2147483647];
# log:
dateNow:2017-12-09 03:49:59 +0000
1970Stamp:1512791399.194478
1970date:2038-01-19 03:14:07 +0000
Integer32 用到2038年就要溢出了,App能再活19年吗
20. 字符串过滤
NSString *string = @" \n sf fds sdfs . .\n ";
NSLog(@"0.=%@", string);
NSLog(@"1.=%@", [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]);
NSLog(@"2.=%@", [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]);
NSLog(@"3.=%@", [self removeSpaceAndNewline:string]);
#log:
0.= _
sf fds sdfs . .
1.=
sf fds sdfs . .
2.=sf fds sdfs . .
3.=sf fds sdfs . .
图片裁剪
图片裁剪用到了core graphics框架 ,此框架下的图像处理坐标系是原点位于左下角,Y轴向上。由于和UIKit坐标系不一样,裁剪时需要考虑进去,并做相应的转换。
- (UIImage *)cropImage:(UIImage*)image toRect:(CGRect)rect {
CGFloat (^rad)(CGFloat) = ^CGFloat(CGFloat deg) {
return deg / 180.0f * (CGFloat) M_PI;
};
// determine the orientation of the image and apply a transformation to the crop rectangle to shift it to the correct position
CGAffineTransform rectTransform;
switch (image.imageOrientation) {
case UIImageOrientationLeft:
rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(90)), 0, -image.size.height);
break;
case UIImageOrientationRight:
rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-90)), -image.size.width, 0);
break;
case UIImageOrientationDown:
rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-180)), -image.size.width, -image.size.height);
break;
default:
rectTransform = CGAffineTransformIdentity;
};
// adjust the transformation scale based on the image scale
rectTransform = CGAffineTransformScale(rectTransform, image.scale, image.scale);
// apply the transformation to the rect to create a new, shifted rect
CGRect transformedCropSquare = CGRectApplyAffineTransform(rect, rectTransform);
// use the rect to crop the image
CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, transformedCropSquare);
// create a new UIImage and set the scale and orientation appropriately
UIImage *result = [UIImage imageWithCGImage:imageRef scale:image.scale orientation:image.imageOrientation];
// memory cleanup
CGImageRelease(imageRef);
return result;
}