1.去除导航栏底部线条和去除Tabbar顶部的线条
我们自定义NavigationController和自定义UITabbar的时候,想去掉他们自带的细线,通过设置下面的可以达到效果
//去除导航栏底部线条
[self.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
[self.navigationBar setShadowImage:[UIImage new]];
//如果上面的达不到效果
//那绘制一个空白的image来设置,亲测两种方法都可以
//去掉下面线条
CGRect rect1 = CGRectMake(0, 0, HFScreenWidth, HFScreenHieght);
UIGraphicsBeginImageContext(rect1.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
CGContextFillRect(context, rect1);
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.navigationBar setBackgroundImage:img forBarMetrics:UIBarMetricsDefault];
[self.navigationBar setShadowImage:img];
//去除Tabbar顶部的线条
[self.tabBar setBackgroundImage:[UIImage new]];
[self.tabBar setShadowImage:[UIImage new]];
//如果上面的达不到效果
//那绘制一个空白的image来设置,亲测两种方法都可以
//去掉下面线条
CGRect rect1 = CGRectMake(0, 0, HFScreenWidth, HFScreenHieght);
UIGraphicsBeginImageContext(rect1.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
CGContextFillRect(context, rect1);
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.tabBar setBackgroundImage: img];
[self.tabBar setShadowImage: img];
2.图片处理
有时候网络加载回来的图片比例有点不适应,这时候就需要我们剪裁处理了,不然的话图片就会被压缩变形
我们可以给UIImageView添加一个类别,然后在类别里面设置contentMode达到效果
//imageview的content适应图片的比例大小,然后再剪裁掉多余的部分
-(void)fitImageView
{
[self setContentScaleFactor:[[UIScreen mainScreen] scale]];
self.contentMode = UIViewContentModeScaleAspectFill;
self .clipsToBounds = YES;
}
//如果图片的frame小于原图大小,显示原图的大小,然后再剪裁掉多余的部分,如果图片的frame大于原图大小,在图片中间显示原图大小
-(void)fitCenterImageView
{
[self setContentScaleFactor:[[UIScreen mainScreen] scale]];
self.contentMode = UIViewContentModeCenter;
self .clipsToBounds = YES;
}
3.导航栏标题和Tabbar标题的设置
//这个单独设置tabbar的title
self.navigationController.title = @"yoyoyo";
//这个单独设置navgation的title
self.navigationItem.title = @"哟哟";
//这个是tabbar和navgation一块设置的
self.title = @"啃爹";
4.给view绘制指定的圆角
使用赛贝尔曲线绘制需要的圆角
typedef NS_OPTIONS(NSUInteger, UIRectCorner) {
UIRectCornerTopLeft = 1 << 0,
UIRectCornerTopRight = 1 << 1,
UIRectCornerBottomLeft = 1 << 2,
UIRectCornerBottomRight = 1 << 3,
UIRectCornerAllCorners = ~0UL
};
CGRect frame = self.backImageView.bounds;
frame.size.width = self.frame.size.width;
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:frame byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight cornerRadii:CGSizeMake(5, 5)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = frame;
maskLayer.path = maskPath.CGPath;
self.backImageView.layer.mask = maskLayer;
5.scrollView传递点击事件
有时候我们会在tableView的cell上面嵌进来scrollview,这时候scrollview就会截取掉,这样tableViewcell的点击事件就无法响应,所以我们需要他点击事件传递下去。给scrollview添加类别,然后重写响应事件,传递到父视图即可
#import "UIScrollView+TouchEvent.h"
@implementation UIScrollView (TouchEvent)
//tableviewcell的scrollview会截取到点击事件,将这个事件传递下去给cell
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//因为collectionView是继承自scrollview,所以如果把collectionview的点击事件也传递下去了,collectionview的点击事件就被其superview接受,没有点击事件了
if ([self isKindOfClass:[UICollectionView class]] || [self isKindOfClass:[UITableView class]]) {
return;
}
[self.superview touchesBegan:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([self isKindOfClass:[UICollectionView class]]||[self isKindOfClass:[UITableView class]]) {
return;
}
[self.superview touchesEnded:touches withEvent:event];
}
@end
6.UITextField和UItextview
1.UITextField的placeholder的字体改变
[self.nameTextView setValue:[UIColor blackColor] forKeyPath:@"_placeholderLabel.color"];
2.改变键盘的类型和return键
self.textField.keyboardType = UIKeyboardTypeNumberPad;
self.textView.returnKeyType = UIReturnKeyDone;
3.捕捉return键响应进行操作
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
if ([text isEqualToString:@"\n"]){ //判断输入的字是否是回车,即按下return
//在这里做你响应return键的代码
[textView resignFirstResponder];
return NO; //这里返回NO,就代表return键值失效,即页面上按下return,不会出现换行,如果为yes,则输入页面会换行
}
return YES;
}
7.横竖屏的转换
//强制横屏
- (void)forceOrientationLandscape
{
AppDelegate *appdelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
appdelegate.allowRotation = 1;
if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
SEL selector = NSSelectorFromString(@"setOrientation:");
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
[invocation setSelector:selector];
[invocation setTarget:[UIDevice currentDevice]];
int val = UIInterfaceOrientationLandscapeRight;
[invocation setArgument:&val atIndex:2];
[invocation invoke];
}
}
//强制竖屏
- (void)forceOrientationPortrait
{
_isDirectionScreen = NO;
AppDelegate *appdelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
appdelegate.allowRotation = 0;
[appdelegate application:[UIApplication sharedApplication] supportedInterfaceOrientationsForWindow:self.view.window];
//设置屏幕的转向为竖屏
[[UIDevice currentDevice] setValue:@(UIDeviceOrientationPortrait) forKey:@"orientation"];
//刷新
[UIViewController attemptRotationToDeviceOrientation];
}
8.调试时打印,正式环境打包不打印
/**
* 调试时打印,正式环境打包不打印
*/
// 日志输出
#ifdef DEBUG
#define HFLog(...) NSLog(__VA_ARGS__)
#else
#define HFLog(...)
#endif
9.常见的基础概念
- Class:定义Objective-C类
- Ivar定义对象的实例变量,包括类型和名字。
- Protocol:定义正式协议。
- objc_property_t:定义属性。叫这个名字可能是为了防止和Objective-C 1.0中的用户类型冲突,那时候还没有属性。
- Method:定义对象方法或类方法。这个类型提供了方法的名字(就是选择器)、参数数量和类型,以及返回值(这些信息合起来称为方法的签名),还有一个指向代码的函数指针(也就是方法的实现)。
- SEL:定义选择器。选择器是方法名的唯一标识符。
- IMP:定义方法实现。这只是一个指向某个函数的指针,该函数接受一个对象、一个选择器和一个可变长参数列表(varargs),返回一个对象
10.缓存URL图片和读取
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
UIImage *image = [UIImage imageWithData:data]; // 取得图片
// 本地沙盒目录
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// 得到本地沙盒中名为"MyImage"的路径,"MyImage"是保存的图片名
NSString *imageFilePath = [path stringByAppendingPathComponent:@"watermark.png"];
NSLog(@"file:%@",imageFilePath);
// 将取得的图片写入本地的沙盒中 UIImageJPEGRepresentation,UIImagePNGRepresentation两种格式存储
BOOL success = [UIImagePNGRepresentation(image) writeToFile:imageFilePath atomically:YES];
if (success){
dispatch_async(dispatch_get_main_queue(), ^{
// 获取图片
NSData *data = [[NSData alloc] initWithContentsOfFile:imageFilePath];
UIImage *waterMarkImage = [UIImage imageWithData:data];
});
}
});
11.获取沙河目录
Documents:保存应用运行时生成的需要持久化的数据,iTunes 同步设备时会备份该目录。例如,游戏应用可 将游戏存档保存在该目录。 tmp:保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也 可能会清除该目录下的文件。iTunes 同步设备时不会备份该目录。 Library/Caches:保存应用运行时生成的需要持久化的数据,iTunes 同步设备时不会备份该目录。一般存储体 积大、不需要备份的非重要数据。
Library/Preference:保存应用的所有偏好设置,iOS 的 Settings(设置)应用会在该目录中查找应用的设置信息。 iTunes 同步设备时会备份该目录。
总结:
1、体积大(itunes 不会备份)
(1) tmp(里面的内容可能会被系统随机清除)
(2) Library/Caches
2、体积小(itunes 会备份)
(1) Documents
(2) Library/Preference
Home目录
NSString *homeDirectory = NSHomeDirectory();
Document目录
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
Cache目录
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
Libaray目录
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
12.openURL
UIApplication 有个功能十分强大的 openURL:方法
- (BOOL)openURL:(NSURL*)url;
openURL:方法的部分功能:
(1)打电话
UIApplication *app = [UIApplication sharedApplication];
[app openURL:[NSURL URLWithString:@"tel://10086"]];
(2)发短信
[app openURL:[NSURL URLWithString:@"sms://10086"]];
(3)发邮件
[app openURL:[NSURL URLWithString:@"mailto://[email protected]"]];
(4)打开一个网页资源(自动跳转到浏览器打开)
[app openURL:[NSURL URLWithString:@"http://ios.itcast.cn"]];
(5)打开其他 app 程序
[app openURL:[NSURL URLWithString:@"........"]];
13.自定义弹出的键盘
self.inputField.inputView = myView
按文本框弹出的键盘不再是普通文字输入键盘,而是我们设置的 myView。一般把这个方法写在 viewDiDLoad 方法中。
也可以在键盘上方增加一个 View:
self. inputField.inputAcessoryView = myView;
之后就可以在键盘上侧显示 myView。
14.判断系统版本
if([[UIDevice currentDevice].systemVersion doubleValue]>=7.0) {
//是 IOS7 至以上版本
}else{
//IOS7 以下版本
}
15.禁止左划手势
if([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = false;
}
自定义导航栏左划返回手势
self.interactivePopGestureRecognizer.delegate = (id)self;
16.KVO
viewcontroller本身不能使用KVO监听其持有的array变化
17.导航栏半透明
导航栏半透明时改变坐标原点
self.automaticallyAdjustsScrollViewInsets = YES;
self.edgesForExtendedLayout = UIRectEdgeNone;
这样设置之后导航栏和tabbar会变灰色而不是半透明,再加上这两个设置就好了
self.navigationController.navigationBar.translucent = NO;
self.tabBarController.tabBar.translucent = NO;
18 oc文件转成c,c++语言文件,后缀名为cpp
cd到你所要转成c语言文件的目录里:
clang -rewrite-objc 目标文件(例如 main.m)
成功会在你所cd的目录下面多了一个后缀名是cpp的文件。
在arc模式下,使用weak修饰符时clang -rewrite-objc xxx.m时会提示编译错误:
cannot create __weak reference because the current deployment target does
not support weak references
__attribute__((objc_ownership(weak))) NSObject *obj2 = obj;
解决方法:
clang -rewrite-objc -fobjc-arc -stdlib=libc++ -mmacosx-version-min=10.7 -fobjc-runtime=macosx-10.7 -Wno-deprecated-declarations 目标文件(例如 main.m)
19.load和initialize
问:Category中有load方法吗?load方法是什么时候调用的?load 方法能继承吗?
答:Category中有load方法,load方法在程序启动装载类信息的时候就会调用。load方法可以继承。调用子类的load方法之前,会先调用父类的load方法
问:load、initialize的区别,以及它们在category重写的时候的调用的次序。
答:区别在于调用方式和调用时刻
调用方式:load是根据函数地址直接调用,initialize是通过objc_msgSend调用
调用时刻:load是runtime加载类、分类的时候调用(只会调用1次),initialize是类第一次接收到消息的时候调用,每一个类只会initialize一次(父类的initialize方法可能会被调用多次)
调用顺序:先调用类的load方法,先编译那个类,就先调用load。在调用load之前会先调用父类的load方法。分类中load方法不会覆盖本类的load方法,先编译的分类优先调用load方法。initialize先初始化父类,之后再初始化子类。如果子类没有实现+initialize,会调用父类的+initialize(所以父类的+initialize可能会被调用多次),如果分类实现了+initialize,就覆盖类本身的+initialize调用。
20.事件传递和事件响应
首先UIApplication会捕获到事件(先进行传递再进行响应),传递到最上层(根据subviews)
然后从最上层开始做响应事件,判断最上层是否能响应事件,如果可以,就响应。无就传递到下一层(nextResponder)往下传递
事件传递:下 ---> 上
事件响应: 上 ---> 下