先说下在项目中遇到问题前,个人的编程习惯:为网络请求建立请求类,为按钮创建类目节省代码量,为网络链接创建头文件,合理运用PCH使代码看起来更简洁.接手一个新项目,快速的调试,查看某个模块或者方法的作用,需要注释掉一个方法,或者某个代码块,直接写return;而不是全选,注释掉.
1、禁止手机睡眠
//方法一
[UIApplication sharedApplication].idleTimerDisabled = YES;
//方法二
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
2、修改xcode文件模板
Finder -> 应用程序-> Xcode ->右键显示包内容,然后可以看到一个content文件夹,我们要找到这个路径下的一个File Templates(文件模版)。
路径为Contents -> Developer -> Platforms -> iPhoneOS.platform -> Developer -> Library -> Xcode -> Templates -> File Templates
大家看到File Templates文件夹下面有五个文件夹,我们需要修改的是Source文件夹下面的Cocoa Touch Class.xctemplate对应的所有文件的.h和.m
3、block避免循环引用的三种方式
block会产生循环引用的原因是block会对其所包含的所有强指针变量强引用一次
//方式1
__weak typeof(self) weakSel = self;
__strong typeof(weakSel) strongeSelf = weakSel;
__weak 通常与 __strong 同时使用 避免因为控制器释放后延迟操作被影响
//方式2
//self的本质是一个指针
__block ViewController *weakSelf = self;
self.block = ^{
NSLog(@"%@",weakSelf);
//不要忘记指针置空
weakSelf = nil;
};
self.block();
//方式3
self.block2 = ^(ViewController *obj){
NSLog(@"%@",obj);
};
self.block2(self);
4、从网页中跳转到自己的 APP 中的方法 (Universal Links)
在系统自带的 Safari 浏览器中输入 scheme 并多加一个冒号和双斜杠,就可以跳转到自己的 APP 当中
5、强制让App直接退出(非闪退,非崩溃)
UIWindow *window = [UIApplication sharedApplication].keyWindow;
[UIView animateWithDuration:1.0f animations:^{
window.alpha = 0;
} completion:^(BOOL finished) {
exit(0);
}];
或者
[[UIApplication sharedApplication] performSelector:@selector(suspend)];
6、删除NSUserDefaults所有记录
//方法一
NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
//方法二
- (void)resetDefaults {
NSUserDefaults * defs = [NSUserDefaults standardUserDefaults];
NSDictionary * dict = [defs dictionaryRepresentation];
for (id key in dict) {
[defs removeObjectForKey:key];
}
[defs synchronize];
}
7、iOS跳转到App Store下载应用评分
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=APPID"]];
8、根据UIView获取所在的UIViewController
方法 1
id responder = self.nextResponder;
while (![responder isKindOfClass: [UIViewController class]] && ![responder isKindOfClass: [UIWindow class]]){
responder = [responder nextResponder];
}
if ([responder isKindOfClass: [UIViewController class]]){
// responder就是view所在的控制器
}
方法 2
- (UIViewController *)getControllerFromView:(UIView *)view {
// 遍历响应者链。返回第一个找到视图控制器
UIResponder *responder = view;
while ((responder = [responder nextResponder])){
if ([responder isKindOfClass: [UIViewController class]]){
return (UIViewController *)responder;
}
}
// 如果没有找到则返回nil
return nil;
}
9、获取一个类的所有子类
+ (NSArray *) allSubclasses
{
Class myClass = [self class];
NSMutableArray *mySubclasses = [NSMutableArray array];
unsigned int numOfClasses;
Class *classes = objc_copyClassList(&numOfClasses;);
for (unsigned int ci = 0; ci < numOfClasses; ci++)
{
Class superClass = classes[ci];
do{
superClass = class_getSuperclass(superClass);
} while (superClass && superClass != myClass);
if (superClass)
{
[mySubclasses addObject: classes[ci]];
}
}
free(classes);
return mySubclasses;
}
10、防止scrollView手势覆盖侧滑手势
创建UIscrollview的类目,然后写以下方法
//是否支持多手势触发,返回YES,则可以多个手势一起触发方法,返回NO则为互斥.
//是否允许多个手势识别器共同识别,一个控件的手势识别后是否阻断手势识别继续向下传播,默认返回NO;如果为YES,响应者链上层对象触发手势识别后,如果下层对象也添加了手势并成功识别也会继续执行,否则上层对象识别后则不再继续传播
//一句话总结就是此方法返回YES时,手势事件会一直往下传递,不论当前层次是否对该事件进行响应。
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if ([self panBack:gestureRecognizer]) {
return YES;
}
return NO;
}
//location_X可自己定义,其代表的是滑动返回距左边的有效长度
- (BOOL)panBack:(UIGestureRecognizer *)gestureRecognizer {
//是滑动返回距左边的有效长度
int location_X =0.15*kSCREENWIDTH;
if (gestureRecognizer ==self.panGestureRecognizer) {
UIPanGestureRecognizer *pan = (UIPanGestureRecognizer *)gestureRecognizer;
CGPoint point = [pan translationInView:self];
UIGestureRecognizerState state = gestureRecognizer.state;
if (UIGestureRecognizerStateBegan == state ||UIGestureRecognizerStatePossible == state) {
CGPoint location = [gestureRecognizer locationInView:self];
//这是允许每张图片都可实现滑动返回
int temp1 = location.x;
int temp2 =kSCREENWIDTH;
NSInteger XX = temp1 % temp2;
if (point.x >0 && XX < location_X) {
return YES;
}
//下面的是只允许在第一张时滑动返回生效
// if (point.x > 0 && location.x < location_X && self.contentOffset.x <= 0) {
// return YES;
// }
}
}
return NO;
}
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
if ([self panBack:gestureRecognizer]) {
return NO;
}
return YES;
}
11、获取手机安装的应用
Class c =NSClassFromString(@"LSApplicationWorkspace");
id s = [(id)c performSelector:NSSelectorFromString(@"defaultWorkspace")];
NSArray *array = [s performSelector:NSSelectorFromString(@"allInstalledApplications")];
for (id item in array)
{
NSLog(@"%@",[item performSelector:NSSelectorFromString(@"applicationIdentifier")]);
//NSLog(@"%@",[item performSelector:NSSelectorFromString(@"bundleIdentifier")]);
NSLog(@"%@",[item performSelector:NSSelectorFromString(@"bundleVersion")]);
NSLog(@"%@",[item performSelector:NSSelectorFromString(@"shortVersionString")]);
}
12、解决NSTimer循环引用的几种方式
1.在视图已经消失的方法中,将定时器销毁掉
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[self.timer invalidate];
self.timer = nil;
}
2.self强引用timer弱引用target
也就是创建定时器的时候,定时器用强引用的 self 修饰,但是在定时器执行的方法中,self 需要用弱引用修饰
__weak typeof(self) weakSelf = self;
3. 借助runtime给对象添加消息处理的能力
_target = [[NSObject alloc] init];
class_addMethod([_target class], @selector(fire), class_getMethodImplementation([self class], @selector(fire)), "v@:");
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:_target selector:@selector(fire) userInfo:nil repeats:YES];
4.通过消息转发的方法的方式
创建一个集成自NSProxy的类PHJProxy 声明一个target
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface PHJProxy : NSProxy
@property (nonatomic, weak) id target;
@end
PHJProxy的实现
@implementation PHJProxy
// 发送给target
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation invokeWithTarget:self.target];
}
// 给target注册一个方法签名
- (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
return [self.target methodSignatureForSelector:sel];
}
@end
PHJProxy 和 NSTimer的使用
self.proxy = [PHJProxy alloc];
self.proxy.target = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self.proxy selector:@selector(fire) userInfo:nil repeats:YES];
其原理为:self强引用timer强引用proxy弱引用self
13、开发中常用通知
// 当程序被推送到后台时
UIKIT_EXTERN NSNotificationName const UIApplicationDidEnterBackgroundNotification NS_AVAILABLE_IOS(4_0);
// 当程序从后台将要重新回到前台时
UIKIT_EXTERN NSNotificationName const UIApplicationWillEnterForegroundNotification NS_AVAILABLE_IOS(4_0);
// 当程序完成载入后通知
UIKIT_EXTERN NSNotificationName const UIApplicationDidFinishLaunchingNotification;
// 应用程序转为激活状态时
UIKIT_EXTERN NSNotificationName const UIApplicationDidBecomeActiveNotification;
// 用户按下主屏幕按钮调用通知,并未进入后台状态
UIKIT_EXTERN NSNotificationName const UIApplicationWillResignActiveNotification;
// 内存较低时通知
UIKIT_EXTERN NSNotificationName const UIApplicationDidReceiveMemoryWarningNotification;
// 当程序将要退出时通知
UIKIT_EXTERN NSNotificationName const UIApplicationWillTerminateNotification;
// 当系统时间发生改变时通知
UIKIT_EXTERN NSNotificationName const UIApplicationSignificantTimeChangeNotification;
// 当StatusBar框方向将要变化时通知
UIKIT_EXTERN NSNotificationName const UIApplicationWillChangeStatusBarOrientationNotification __TVOS_PROHIBITED; // userInfo contains NSNumber with new orientation
// 当StatusBar框方向改变时通知
UIKIT_EXTERN NSNotificationName const UIApplicationDidChangeStatusBarOrientationNotification __TVOS_PROHIBITED; // userInfo contains NSNumber with old orientation
// 当StatusBar框Frame将要改变时通知
UIKIT_EXTERN NSNotificationName const UIApplicationWillChangeStatusBarFrameNotification __TVOS_PROHIBITED; // userInfo contains NSValue with new frame
// 当StatusBar框Frame改变时通知
UIKIT_EXTERN NSNotificationName const UIApplicationDidChangeStatusBarFrameNotification __TVOS_PROHIBITED; // userInfo contains NSValue with old frame
// 后台下载状态发生改变时通知(iOS7.0以后可用)
UIKIT_EXTERN NSNotificationName const UIApplicationBackgroundRefreshStatusDidChangeNotification NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED;
// 受保护的文件当前变为不可用时通知
UIKIT_EXTERN NSNotificationName const UIApplicationProtectedDataWillBecomeUnavailable NS_AVAILABLE_IOS(4_0);
// 受保护的文件当前变为可用时通知
UIKIT_EXTERN NSNotificationName const UIApplicationProtectedDataDidBecomeAvailable NS_AVAILABLE_IOS(4_0);
// 截屏通知(iOS7.0以后可用)
UIKIT_EXTERN NSNotificationName const UIApplicationUserDidTakeScreenshotNotification NS_AVAILABLE_IOS(7_0);
UIKeyboardWillShowNotification // 键盘即将显示
UIKeyboardDidShowNotification // 键盘显示完毕
UIKeyboardWillHideNotification // 键盘即将隐藏
UIKeyboardDidHideNotification // 键盘隐藏完毕
14、自定义设置状态栏背景颜色
/** 自定义设置状态栏背景颜色 */
- (void)setStatusBarBackgroundColor:(UIColor *)color {
UIView *statusBar = [[[UIApplication sharedApplication] valueForKey:@"statusBarWindow"] valueForKey:@"statusBar"];
if ([statusBar respondsToSelector:@selector(setBackgroundColor:)]){
statusBar.backgroundColor = color;
}
}
15、自定义通知的标准写法
// 声明文件
UIKIT_EXTERN NSNotificationName const ZOCFooDidBecomeBarNotification;
// 实现文件
NSNotificationName const ZOCFooDidBecomeBarNotification = @"ZOCFooDidBecomeBarNotification";
16、navigationBar下面的横线
首先说明下其实这是shadoImage 在作怪,这道横线,其实是NaVigationBar下产生的阴影效果,贴在一起就出现了横线的样式.因此,只要去掉阴影效果即可.而且我们也可以用同样的方法来去掉tabbar上面的横线
[self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
//消除阴影
self.navigationController.navigationBar.shadowImage = [UIImage new];
//去除UINavigationBar的黑线
[[UINavigationBar appearance]setShadowImage:[UIImage new]];
[[UINavigationBar appearance]setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
//去除UITabBar的黑线
[[UITabBar appearance]setShadowImage:[UIImage new]];
[[UITabBar appearance]setBackgroundImage:[UIImage new]];
17、表视图的分割线向左顶格显示
通常我们用的表视图的分割线并不是左右两边都顶格显示的,应该是从左边15的距离开始显示的,但是有时候我们就想让分割线顶格,这时候就需要将分割线左移15
首先在viewDidLoad方法中加上如下代码:
if ([tableView respondsToSelector:@selector(setSeparatorInset:)]) {
[tableView setSeparatorInset: UIEdgeInsetsZero];
}
if ([tableView respondsToSelector:@selector(setLayoutMargins:)]) {
[tableView setLayoutMargins: UIEdgeInsetsZero];
}
然后再加上这个方法:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([cell respondsToSelector:@selector(setSeparatorInset:)]) {
[cell setSeparatorInset:UIEdgeInsetsZero];
}
if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
[cell setLayoutMargins:UIEdgeInsetsZero];
}
}
当然,也可以在在自定义的cell视图里重写父视图的setFrame方法进行设置,方法很多,并不是固定的
18、同时识别多个手势,解决因为 ScrollView 横向滑动造成的与手势返回的冲突问题
//在 navigationcontroller 基类中添加上如下方法即可
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;
}
19、使用终端查询哪个 SDK 使用了 UIWebView 的 API
首先要 cd进入到工程的根目录,然后输入如下命令
grep -r "UIWebView" .
20、获取目标视图在window坐标系的frame
//获取目标视图在window坐标系的frame
CGRect rect = [self.view convertRect:self.wobBtn.frame toView:[UIApplication sharedApplication].keyWindow];
UIBezierPath *path = [UIBezierPath bezierPathWithRect:frame];
[path appendPath:[[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:5] bezierPathByReversingPath]];
// bezierPathByReversingPath 的意思就是反转 就是将你设置的路径以外的部分加入到路径中这样 你设置的路径就不在绘制的范围之内。在setMaskLayer的时候 你设置的那部分路径就没有了 就成了镂空的。 clockwise 这个值得意思也是这样。
21、动画效果切换根视图
[UIView transitionWithView:[UIApplication sharedApplication].keyWindow duration:0.5f options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
BOOL oldState = [UIView areAnimationsEnabled];
[UIView setAnimationsEnabled:NO];
[UIApplication sharedApplication].keyWindow.rootViewController = [[TabViewController alloc]init];
[UIView setAnimationsEnabled:oldState];
} completion:^(BOOL finished) {
}];
//或者
[UIView transitionFromView:self.view toView:chatVC.view duration:1 options:UIViewAnimationOptionTransitionFlipFromBottom completion:^(BOOL finished) {
}];
22、当我们想要在闪屏界面多显示一段时间时,需要阻塞主线程
//延迟五秒 方法1
[NSThread sleepForTimeInterval:5];
//延迟五秒 方法2
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:5]];
23、简单的图文混排
-(NSMutableAttributedString *)setTextAttachmentImageName:(NSString *)attachImage andText:(NSString *)text{
NSMutableAttributedString *textAttrStr = [[NSMutableAttributedString alloc] init];
NSTextAttachment *attach = [[NSTextAttachment alloc] init];
attach.image = [UIImage imageNamed:attachImage];
//font.lineHeight 该字体大小所对应的行高
attach.bounds = CGRectMake(KScale(-2), KScale(-2) ,KScale(12), KScale(12));
NSAttributedString *imgStr = [NSAttributedString attributedStringWithAttachment:attach];
[textAttrStr appendAttributedString:[[NSAttributedString alloc] initWithString:text]];
[textAttrStr appendAttributedString:imgStr];
return textAttrStr;
}
24、颜色转图片
-(UIImage *)cl_imageWithColor:(UIColor *)color {
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
25、Runtime常用 API
// 1.objc_xxx 系列函数
objc_getClass 获取Class对象
objc_getMetaClass 获取MetaClass对象
objc_allocateClassPair 分配空间,动态的创建一个类(仅在 创建之后,注册之前 能够添加成员变量)
objc_registerClassPair 注册一个类(注册后方可使用该类创建对象,要在注册之前添加成员变量)
objc_disposeClassPair 注销某个类
objc_allocateProtocol 开辟空间创建协议
objc_registerProtocol 注册一个协议
objc_constructInstance 构造一个实例对象(ARC下无效)
objc_destructInstance 析构一个实例对象(ARC下无效)
objc_setAssociatedObject 为实例对象关联对象
objc_getAssociatedObje*ct 获取实例对象的关联对象
objc_removeAssociatedObjects 清空实例对象的所有关联对象
objc_系列函数关注于宏观使用,如类与协议的空间分配,注册,注销等操作
// 2.class_xxx 系列函数
class_addIvar 为类添加实例变量
class_addProperty 为类添加属性
class_addMethod 为类添加方法
class_addProtocol 为类遵循协议
class_replaceMethod 替换类某方法的实现
class_getName 获取类名
class_isMetaClass 判断是否为元类
objc_getProtocol 获取某个协议
objc_copyProtocolList 拷贝在运行时中注册过的协议列表
class_getSuperclass 获取某类的父类
class_setSuperclass 设置某类的父类
class_getProperty 获取某类的属性
class_getInstanceVariable 获取实例变量
class_getClassVariable 获取类变量
class_getInstanceMethod 获取实例方法
class_getClassMethod 获取类方法
class_getMethodImplementation 获取方法的实现
class_getInstanceSize 获取类的实例的大小
class_respondsToSelector 判断类是否实现某方法
class_conformsToProtocol 判断类是否遵循某协议
class_createInstance 创建类的实例
class_copyIvarList 拷贝类的实例变量列表
class_copyMethodList 拷贝类的方法列表
class_copyProtocolList 拷贝类遵循的协议列表
class_copyPropertyList 拷贝类的属性列表
class_系列函数关注于类的内部,如实例变量,属性,方法,协议等相关问题
// 3.object_xxx 系列函数
object_copy 对象copy(ARC无效)
object_dispose 对象释放(ARC无效)
object_getClassName 获取对象的类名
object_getClass 获取对象的Class(获取 isa 指针指向的类)
object_setClass 设置对象的Class(设置 isa 指针指向的类)
object_isClass 判断一个 Class是否为元类
object_isMetaClass 判断一个 oc 对象是否为 Class
object_getSuperClass 获取父类
object_getIvar 获取对象中实例变量的值
object_setIvar 设置对象中实例变量的值
object_getInstanceVariable 获取对象中实例变量的值 (ARC中无效,使用object_getIvar)
object_setInstanceVariable 设置对象中实例变量的值 (ARC中无效,使用object_setIvar)
objcet_系列函数关注于对象的角度,如实例变量
// 4.method_xxx 系列函数
method_getName 获取方法名
method_getImplementation 获取方法的实现
method_getTypeEncoding 获取方法的类型编码
method_getNumberOfArguments 获取方法的参数个数
method_copyReturnType 拷贝方法的返回类型
method_getReturnType 获取方法的返回类型
method_copyArgumentType 拷贝方法的参数类型
method_getArgumentType 获取方法的参数类型
method_getDescription 获取方法的描述
method_setImplementation 设置方法的实现
method_exchangeImplementations 替换方法的实现
method_系列函数关注于方法内部,如果方法的参数及返回值类型和方法的实现
// 5.property_xxx 系列函数
property_getName 获取属性名
property_getAttributes 获取属性的特性列表
property_copyAttributeList 拷贝属性的特性列表
property_copyAttributeValue 拷贝属性中某特性的值
property_系类函数关注与属性*内部,如属性的特性等
// 6.protocol_xxx 系列函数
protocol_conformsToProtocol 判断一个协议是否遵循另一个协议
protocol_isEqual 判断两个协议是否一致
protocol_getName 获取协议名称
protocol_copyPropertyList 拷贝协议的属性列表
protocol_copyProtocolList 拷贝某协议所遵循的协议列表
protocol_copyMethodDescriptionList 拷贝协议的方法列表
protocol_addProtocol 为一个协议遵循另一协议
protocol_addProperty 为协议添加属性
protocol_getProperty 获取协议中的某个属性
protocol_addMethodDescription 为协议添加方法描述
protocol_getMethodDescription 获取协议中某方法的描述
// 7.ivar_xxx 系列函数
ivar_getName 获取Ivar名称
ivar_getTypeEncoding 获取类型编码
ivar_getOffset 获取偏移量
// 8.sel_xxx 系列函数
sel_getName 获取名称
sel_getUid 注册方法
sel_registerName 注册方法
sel_isEqual 判断方法是否相等
// 9.imp_xxx 系列函数
imp_implementationWithBlock 通过代码块创建IMP
imp_getBlock 获取函数指针中的代码块
imp_removeBlock 移除IMP中的代码块
26、修改UITextField的placeholder颜色
方法1、使用富文本
@property(nonatomic,copy) NSAttributedString *attributedPlaceholder;
// 文字属性
NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
attrs[NSForegroundColorAttributeName] = [UIColor grayColor];
// NSAttributedString : 带有属性的文字(富文本技术)
NSAttributedString *placeholder = [[NSAttributedString alloc] initWithString:@"手机号" attributes:attrs];
self.phoneField.attributedPlaceholder = placeholder;
NSMutableAttributedString *placehoder = [[NSMutableAttributedString alloc] initWithString:@"手机号"];
[placehoder setAttributes:@{NSForegroundColorAttributeName : [UIColor whiteColor]} range:NSMakeRange(0, 1)];
[placehoder setAttributes:@{
NSForegroundColorAttributeName : [UIColor yellowColor],
NSFontAttributeName : [UIFont systemFontOfSize:30]
} range:NSMakeRange(1, 1)];
[placehoder setAttributes:@{NSForegroundColorAttributeName : [UIColor redColor]} range:NSMakeRange(2, 1)];
self.phoneField.attributedPlaceholder = placehoder;
方法2、重写方法
- (void)drawPlaceholderInRect:(CGRect)rect
{
[self.placeholder drawInRect:CGRectMake(0, 10, rect.size.width, 25) withAttributes:@{
NSForegroundColorAttributeName : [UIColor grayColor],
NSFontAttributeName : self.font}];
}
方法3、用KVC
[textField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];
//同理还可以修改textField的placeholder的字体大小
[textField setValue:[UIFont boldSystemFontOfSize:16] forKeyPath:@"_placeholderLabel.font"];
27、给定的数字翻转
-(int)reverse:(int)number{
int result = 0;
while (number) {
result = result * 10 + number % 10;
number = number / 10;
}
return result;
}
28、控制屏幕旋转,在控制器中写
/** 是否支持自动转屏 */
- (BOOL)shouldAutorotate {
return YES;
}
/** 支持哪些屏幕方向 */
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
}
/** 默认的屏幕方向(当前ViewController必须是通过模态出来的UIViewController(模态带导航的无效)方式展现出来的,才会调用这个方法) */
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationLandscapeLeft | UIInterfaceOrientationLandscapeRight;
}
29、将顶部navigationbar设置为透明,但是返回按钮和标题不透明
//iOS 11之前
[[[self.navigationController.navigationBar subviews] objectAtIndex:0] setAlpha:0];
//iOS11以后
UIView * barBackground = self.navigationController.navigationBar.subviews.firstObject;
if (@available(iOS 11.0, *))
{
[barBackground.subviews setValue:@(0) forKeyPath:@"alpha"];
} else {
barBackground.alpha = 0;
}
如果想像QQ空间或者微博那样动态的改变透明度,只需要在scrollViewDidScroll方法中,动态去设置alpha值就行,何时开始改变、变化率全凭自定义的参数控制.
//通常还要取消滚动视图的自适应尺寸
self.automaticallyAdjustsScrollViewInsets = NO;
static CGFloat alpha = 0;
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
if (scrollView == _tableView) {
alpha = scrollView.contentOffset.y/400;
alpha = (alpha <= 0)?0:alpha;
alpha = (alpha >= 1)?1:alpha;
//设置bar的颜色
self.navigationController.navigationBar.barTintColor = [UIColor orangeColor];
//设置透明度
[[[self.navigationController.navigationBar subviews]objectAtIndex:0] setAlpha:alpha];
}
}
30、关闭滚动视图的自动布局
self.automaticallyAdjustsScrollViewInsets = NO;
还有一种方式也可以关闭自适应,利用了edgeInset内嵌边距,tableView的frame依旧是全屏尺寸的,只是设置了下contentInset使得其内容视图的尺寸改变了,scrollIndicatorInsets是右侧的滑动指示器,要跟着一起才自然。如果当前页还有tabBar的话,只需要设置UIEdgeInsetsMake的bottom值就行
_tableView.contentInset = UIEdgeInsetsMake(64, 0, 0, 0);
还可以这么写
self.edgesForExtendedLayout = UIRectEdgeNone;
31、拖动表视图时,松手再判断是否隐藏navigationbar
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{
NSLog(@"======== %lf", velocity.y);
if(velocity.y > 0) {
[self.navigationController setNavigationBarHidden:YES animated:YES];
}
else {
[self.navigationController setNavigationBarHidden:NO animated:YES];
}
}
说明一下:velocity.y这个量,在上滑和下滑时,变化极小(小数),但是因为方向不同,有正负之分,这就很好处理了。
32、拖动表视图时,不松手就判断是否隐藏navigationbar
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
CGFloat offsetY = scrollView.contentOffset.y + _tableView.contentInset.top;
//注意:panTranslationY是scrollView的pan手势的手指位置的y值,这个方法是个人自己想到的,可能不是太好,因为panTranslationY这个值在较小幅度上下滑动时,可能都为正或都为负,这就使得这一方式不太灵敏
CGFloat panTranslationY = [scrollView.panGestureRecognizer translationInView:self.tableView].y;
//这里的offsetY > 64只是为了在视图滑过navigationBar的高度之后才开始处理,防止影响展示效果。
if (offsetY > 64) {
if (panTranslationY > 0) { //下滑趋势,显示
[self.navigationController setNavigationBarHidden:NO animated:YES];
}
else { //上滑趋势,隐藏
[self.navigationController setNavigationBarHidden:YES animated:YES];
}
}
else {
[self.navigationController setNavigationBarHidden:NO animated:YES];
}
}
33、设置应用内的系统控件语言
有时候我们用系统的播放器的时候,完成的done这个按钮显得格外碍眼,怎么变成汉字呢?就用这个方法,在info.plist文件中添加下列内容
<key>CFBundleLocalizations</key>
<array>
<string>zh_CN</string>
<string>en</string>
</array>
34、获取开屏LaunchScreen对象
在给App加入开屏广告时,发现LaunchScreen和开屏广告衔接处需要通过一张截图来过渡. 但是不同尺寸的屏幕上得放不同截图,可以直接用LaunchScreen 作为截图
//拿到LaunchScreen.StoryBoard并生成一个控制器
UIViewController *stvc = [[UIStoryboard storyboardWithName:@"LaunchScreen" bundle:[NSBundle mainBundle]] instantiateInitialViewController];
//通过控制器的.view生成imgae截图
CGRect rect = stvc.view.bounds;
UIGraphicsBeginImageContextWithOptions(rect.size, YES, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
[view.layer renderInContext:context];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//之后拿到了image就可以用作开屏广告前的截图了,比如腾讯广告中就会用到
[TXAD configOpenScreenAD:image fullImg:image placementId:TAD_OpenScreenPlaceId];
35、设置UIView的某几个角为圆角
UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(200, 200, 80, 80)];
view2.backgroundColor = [UIColor redColor];
[self.view addSubview:view2];
//UIRectCornerBottomLeft -> 左下角 依此类推。
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view2.bounds byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight cornerRadii:CGSizeMake(10, 10)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = view2.bounds;
maskLayer.path = maskPath.CGPath;
view2.layer.mask = maskLayer;
36、获得UIButton的当前状态
//UIButton有很多种状态,它提供了一些便捷属性,可以直接获取当前状态下的文字、文字颜色、图片等
@property(nullable, nonatomic,readonly,strong) NSString *currentTitle;
@property(nonatomic,readonly,strong) UIColor *currentTitleColor;
@property(nullable, nonatomic,readonly,strong) UIColor *currentTitleShadowColor;
@property(nullable, nonatomic,readonly,strong) UIImage *currentImage;
@property(nullable, nonatomic,readonly,strong) UIImage *currentBackgroundImage;
@property(nullable, nonatomic,readonly,strong) NSAttributedString *currentAttributedTitle NS_AVAILABLE_IOS(6_0);
你也可以获取不是当前状态的标题、颜色和背景图片
- (nullable NSString *)titleForState:(UIControlState)state; // these getters only take a single state value
- (nullable UIColor *)titleColorForState:(UIControlState)state;
- (nullable UIColor *)titleShadowColorForState:(UIControlState)state;
- (nullable UIImage *)imageForState:(UIControlState)state;
- (nullable UIImage *)backgroundImageForState:(UIControlState)state;
- (nullable NSAttributedString *)attributedTitleForState:(UIControlState)state NS_AVAILABLE_IOS(6_0);
37、导航栏的返回按钮只保留那个箭头,去掉后边的文字
[[UIBarButtonItem appearance]setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -60) forBarMetrics:UIBarMetricsDefault];
38、有时候当我们在工程中导入第三方的库之后,可能会遇到''The file “XXX.app” couldn’t be opened because you don’t have permission to view it.''的情况,其原因为:info文件中的字段Executable file 与 build settings栏中的Packaging中的Product Name 不一致.解决方法是
将info.plist的文件中的Executable.file中的文件修改为:$(PRODUCT_NAME)
39、将手势穿透到下一个视图
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
[[self nextResponder] touchesBegan:touches withEvent:event];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
[[self nextResponder] touchesMoved:touches withEvent:event];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
[[self nextResponder] touchesEnded:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(nullable UIEvent *)event
{
[super touchesCancelled:touches withEvent:event];
[[self nextResponder]touchesCancelled:touches withEvent:event];
}
40、跳转到各种系统的设置界面.
例如:@"无线局域网",@"蓝牙",@"个人热点",@"运营商",@"通知",@"睡眠",@"通用",@"调节亮度",@"墙纸",@"声音",@"siri语音助手",@"隐私",@"电话",@"icloud",@"iTunes Strore 与 APP Store",@"safari",@"关于本机",@"软件更新",@"辅助功能",@"日期与时间",@"键盘",@"存储空间",@"语言与地区",@"VPN",@"描述文件与设备管理",@"音乐",@"备忘录",@"照片与相机",@"还原",@"Twiter",@"Facebook"
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"App-Prefs:root=Bluetooth"]];
/*
case 0://无线局域网
jump(url: "App-prefs:root=WIFI")
case 1: //蓝牙
jump(url: "App-Prefs:root=Bluetooth")
case 2: //个人热点
jump(url: "App-prefs:root=INTERNET_TETHERING")
case 3: //运营商
jump(url: "App-prefs:root=Carrier")
case 4: //通知:需要大写后面加上ID
jump(url: "App-prefs:root=NOTIFICATIONS_ID")
case 5: //睡眠
jump(url: "App-prefs:root=DO_NOT_DISTURB")
case 6: //通用
jump(url: "App-prefs:root=General")
case 7: //调节亮度
jump(url: "App-prefs:root=DISPLAY&BRIGHTNESS")
case 8://墙纸
jump(url: "App-prefs:root=Wallpaper")
case 9://声音
jump(url: "App-prefs:root=Sounds")
case 10://siri语音助手
jump(url: "App-prefs:root=SIRI")
case 11://隐私
jump(url: "App-prefs:root=Privacy")
case 12: //电话
jump(url: "App-prefs:root=Phone")
case 13: //icloud
jump(url: "App-prefs:root=CASTLE")
case 14://iTunes Strore 与 APP Store
jump(url: "App-prefs:root=STORE")
case 15://safari
jump(url: "App-prefs:root=SAFARI")
case 16: //关于本机
jump(url: "App-prefs:root=General&path=About")
case 17://软件更新
jump(url: "App-prefs:root=General&path=SOFTWARE_UPDATE_LINK")
case 18: //辅助功能
jump(url: "App-prefs:root=General&path=ACCESSIBILITY")
case 19: //日期与时间
jump(url: "App-prefs:root=General&path=DATE_AND_TIME")
case 20: //键盘
jump(url: "App-prefs:root=General&path=Keyboard")
case 21://存储空间
jump(url: "App-prefs:root=CASTLE&path=STORAGE_AND_BACKUP")
case 22: //语言与地区
jump(url: "App-prefs:root=General&path=Language_AND_Region")
case 23://VPN
jump(url: "App-prefs:root=General&path=VPN")
case 24://描述文件与设备管理
jump(url: "App-prefs:root=General&path=ManagedConfigurationList")
case 25://音乐
jump(url: "App-prefs:root=MUSIC")
case 26://备忘录
jump(url: "App-prefs:root=NOTES")
case 27: //照片与相机
jump(url: "App-prefs:root=Photos")
case 28://还原
jump(url: "App-prefs:root=General&path=Reset")
case 29: //Twiter
jump(url: "App-prefs:root=TWITTER")
case 30: //Facebook
jump(url: "App-prefs:root=FACEBOOK")
*/
41、计算几个月后的今天
//计算几个月后的今天
NSDate *date = [NSDate date];
date = [self dateAfterMonths:date gapMonth:2];
NSLog(@"😁%@",date);
//
- (NSDate *)dateAfterMonths:(NSDate *)currentDate gapMonth:(NSInteger)gapMonthCount {
//获取当年的月份,当月的总天数
NSCalendar *calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitCalendar fromDate:currentDate];
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setDateStyle:NSDateFormatterFullStyle];
[formatter setDateFormat:@"yyyy-MM-dd"];
[formatter setTimeZone:[NSTimeZone localTimeZone]];
[formatter setTimeZone:[NSTimeZone timeZoneWithName:@"Asia/Shanghai"]];
NSString *dateStr = @"";
NSInteger endDay = 0;//天
NSDate *newDate = [NSDate date];//新的年&月
//判断是否是下一年
if (components.month+gapMonthCount > 12) {
//是下一年
dateStr = [NSString stringWithFormat:@"%zd-%zd-01",components.year+(components.month+gapMonthCount)/12,(components.month+gapMonthCount)%12];
newDate = [formatter dateFromString:dateStr];
//新月份的天数
NSInteger newDays = [calendar rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:newDate].length;
if ([self isEndOfTheMonth:currentDate]) {//当前日期处于月末
endDay = newDays;
} else {
endDay = newDays < components.day?newDays:components.day;
}
dateStr = [NSString stringWithFormat:@"%zd-%zd-%zd",components.year+(components.month+gapMonthCount)/12,(components.month+gapMonthCount)%12,endDay];
} else {
//依然是当前年份
dateStr = [NSString stringWithFormat:@"%zd-%zd-01",components.year,components.month+gapMonthCount];
newDate = [formatter dateFromString:dateStr];
//新月份的天数
NSInteger newDays = [calendar rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:newDate].length;
if ([self isEndOfTheMonth:currentDate]) {//当前日期处于月末
endDay = newDays;
} else {
endDay = newDays < components.day?newDays:components.day;
}
dateStr = [NSString stringWithFormat:@"%zd-%zd-%zd",components.year,components.month+gapMonthCount,endDay];
}
newDate = [formatter dateFromString:dateStr];
return newDate;
}
//判断是否是月末
- (BOOL)isEndOfTheMonth:(NSDate *)date {
NSCalendar *calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
NSInteger daysInMonth = [calendar rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:date].length;
NSDateComponents *componets = [calendar components:NSCalendarUnitDay fromDate:date];
if (componets.day >= daysInMonth) {
return YES;
}
return NO;
}
42、筛选掉文本中所有的非数字
- (void)textDidChanged: (UITextField *)textField{
NSMutableString * modifyText = textField.text.mutableCopy;
for (NSInteger idx = 0; idx < modifyText.length; idx++) {
NSString * subString = [modifyText substringWithRange: NSMakeRange(idx, 1)];
// 使用正则表达式筛选
NSString * matchExp = @"^\\d$";
NSPredicate * predicate = [NSPredicate predicateWithFormat: @"SELF MATCHES %@", matchExp];
if ([predicate evaluateWithObject: subString]) {
idx++;
} else {
[modifyString deleteCharactersInRange: NSMakeRange(idx, 1)];
}
}
}
43、为textView添加placeholderLabel
UILabel *placeHolderLabel = [[UILabel alloc] init];
placeHolderLabel.text = @"在此输入您要反馈的内容哦~";
placeHolderLabel.numberOfLines = 0;
placeHolderLabel.textColor = [UIColor lightGrayColor];
[placeHolderLabel sizeToFit];
[self.textView addSubview:placeHolderLabel];//这句很重要不要忘了
self.textView.font = [UIFont systemFontOfSize:20.f];
placeHolderLabel.font = [UIFont systemFontOfSize:20.f];
//KVC
[self.textView setValue:placeHolderLabel forKey:@"_placeholderLabel"];
44、占位
45、TextView的字数限制
#define MaxNumberOfDescriptionChars 150
-(void)textViewEditChanged:(NSNotification *)obj{
UITextView *textView = (UITextView *)obj.object;
NSString *toBeString = textView.text;
NSString *lang = [[UITextInputMode currentInputMode] primaryLanguage]; // 键盘输入模式
if ([lang isEqualToString:@"zh-Hans"]) { // 简体中文输入,包括简体拼音,健体五笔,简体手写
UITextRange *selectedRange = [textView markedTextRange];
//获取高亮部分
UITextPosition *position = [textView positionFromPosition:selectedRange.start offset:0];
// 没有高亮选择的字,则对已输入的文字进行字数统计和限制
if (!position) {
if (toBeString.length > MaxNumberOfDescriptionChars) {
textView.text = [toBeString substringToIndex:MaxNumberOfDescriptionChars];
}
}
// 有高亮选择的字符串,则暂不对文字进行统计和限制
else{
}
}
// 中文输入法以外的直接对其统计限制即可,不考虑其他语种情况
else{
if (toBeString.length > MaxNumberOfDescriptionChars) {
textView.text = [toBeString substringToIndex:MaxNumberOfDescriptionChars];
}
}
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
NSString *new = [textView.text stringByReplacingCharactersInRange:range withString:text];
self.numLabel.text = [NSString stringWithFormat:@"%zd字",(MaxNumberOfDescriptionChars - new.length)];
if(new.length > MaxNumberOfDescriptionChars){
self.numLabel.text = [NSString stringWithFormat:@"%zd字",0];
if (![text isEqualToString:@""]) {
return NO;
}
}
return YES;
}
46、占位
47、Swift中 Log输出
func printLog<T>(_ message: T, file: String = #file, method: String = #function, line:Int = #line) {
#if DEBUG
print("\((file as NSString).lastPathComponent)[\(line)], \(method): \(message)")
#endif
}
48、将HTML字符串转化为NSAttributedString富文本字符串
- (NSAttributedString *)attributedStringWithHTMLString:(NSString *)htmlString
{
NSDictionary *options = @{ NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute :@(NSUTF8StringEncoding) };
NSData *data = [htmlString dataUsingEncoding:NSUTF8StringEncoding];
return [[NSAttributedString alloc] initWithData:data options:options documentAttributes:nil error:nil];
}
49、CABasicAnimation(CAKeyframeAnimation)key path 取值
keyPath可以使用的key
- define angle2Radian(angle) ((angle)/180.0*M_PI)
transform.rotation.x 围绕x轴翻转 参数:角度 angle2Radian(4)
transform.rotation.y 围绕y轴翻转 参数:同上
transform.rotation.z 围绕z轴翻转 参数:同上
transform.rotation 默认围绕z轴
transform.scale.x x方向缩放 参数:缩放比例 1.5
transform.scale.y y方向缩放 参数:同上
transform.scale.z z方向缩放 参数:同上
transform.scale 所有方向缩放 参数:同上
transform.translation.x x方向移动 参数:x轴上的坐标 100
transform.translation.y x方向移动 参数:y轴上的坐标
transform.translation.z x方向移动 参数:z轴上的坐标
transform.translation 移动 参数:移动到的点 (100,100)
opacity 透明度 参数:透明度 0.5
backgroundColor 背景颜色 参数:颜色 (id)[[UIColor redColor] CGColor]
cornerRadius 圆角 参数:圆角半径 5
borderWidth 边框宽度 参数:边框宽度 5
bounds 大小 参数:CGRect
contents 内容 参数:CGImage
contentsRect 可视内容 参数:CGRect 值是0~1之间的小数
hidden 是否隐藏
position
shadowColor
shadowOffset
shadowOpacity
shadowRadius
50、将项目中的PCH文件路径转化为相对路径,格式如下
$(PRODUCT_NAME)/PrefixHeader.pch
或者
$(SRCROOT)/项目名/PrefixHeader.pch
51、截屏
-(void)ScreenShot{
CGSize imageSize = [[UIScreen mainScreen] bounds].size;
if (NULL != &UIGraphicsBeginImageContextWithOptions) {
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
}
CGContextRef context = UIGraphicsGetCurrentContext();
for (UIWindow * window in [[UIApplication sharedApplication] windows]) {
if (![window respondsToSelector:@selector(screen)] || [window screen] == [UIScreen mainScreen]) {
CGContextSaveGState(context);
CGContextTranslateCTM(context, [window center].x, [window center].y);
CGContextConcatCTM(context, [window transform]);
CGContextTranslateCTM(context, -[window bounds].size.width*[[window layer] anchorPoint].x, -[window bounds].size.height*[[window layer] anchorPoint].y);
[[window layer] renderInContext:context];
CGContextRestoreGState(context);
}
}
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);//保存图片到照片库
NSData *imageViewData = UIImagePNGRepresentation(image);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pictureName= [NSString stringWithFormat:@"screenShow_%d.png",3];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:pictureName];
NSLog(@"截屏路径打印: %@", savedImagePath);
//保存照片到沙盒目录
//CGImageRelease(imageRefRect);
[imageViewData writeToFile:savedImagePath atomically:YES];
NSLog(@"截屏成功!");
}
52、占位
53、NSDictionaryOfVariableBindings这个宏生成一个字典,这个宏可以生成一个变量名到变量值映射的Dictionary,以后字典可以这样写:
NSNumber * packId=@(2);
NSNumber *userId=@(22);
NSNumber *proxyType=@(2);
NSDictionary *param=NSDictionaryOfVariableBindings(packId,userId,proxyType);
54、长按web上面的图片进行保存
首先遵守UIGestureRecognizerDelegate和NSURLSessionDelegate协议
//在viewDidLoad给UIWebView添加手势
UILongPressGestureRecognizer* longPressed = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressed:)];
longPressed.delegate = self;
[self.webView addGestureRecognizer:longPressed];
实现以下方法
#pragma mark -- UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;
}
- (void)longPressed:(UILongPressGestureRecognizer*)recognizer{
if (recognizer.state != UIGestureRecognizerStateBegan) {
return;
}
CGPoint touchPoint = [recognizer locationInView:self.webView];
NSString *imgURL = [NSString stringWithFormat:@"document.elementFromPoint(%f, %f).src", touchPoint.x, touchPoint.y];
NSString *urlToSave = [self.webView stringByEvaluatingJavaScriptFromString:imgURL];
if (urlToSave.length == 0) {
return;
}
UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"大宝贝儿" message:@"你真的要保存图片到相册吗?" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"真的啊" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self saveImageToDiskWithUrl:urlToSave];
}];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"大哥,我点错了,不好意思" style:UIAlertActionStyleDefault handler:nil];
[alertVC addAction:okAction];
[alertVC addAction:cancelAction];
[self presentViewController:alertVC animated:YES completion:nil];
}
#pragma mark - private method
- (void)saveImageToDiskWithUrl:(NSString *)imageUrl{
NSURL *url = [NSURL URLWithString:imageUrl];
NSURLSessionConfiguration * configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue new]];
NSURLRequest *imgRequest = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30.0];
NSURLSessionDownloadTask *task = [session downloadTaskWithRequest:imgRequest completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
return ;
}
NSData * imageData = [NSData dataWithContentsOfURL:location];
dispatch_async(dispatch_get_main_queue(), ^{
UIImage * image = [UIImage imageWithData:imageData];
UIImageWriteToSavedPhotosAlbum(image, self, @selector(imageSavedToPhotosAlbum:didFinishSavingWithError:contextInfo:), NULL);
});
}];
[task resume];
}
#pragma mark 保存图片后的回调
- (void)imageSavedToPhotosAlbum:(UIImage*)image didFinishSavingWithError: (NSError*)error contextInfo:(id)contextInfo{
NSString*message =@"嘿嘿";
if(!error) {
UIAlertController *alertControl = [UIAlertController alertControllerWithTitle:@"提示" message:@"成功保存到相册" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *action = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDestructive handler:nil];
[alertControl addAction:action];
[self presentViewController:alertControl animated:YES completion:nil];
}else{
message = [error description];
UIAlertController *alertControl = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *action = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:nil];
[alertControl addAction:action];
[self presentViewController:alertControl animated:YES completion:nil];
}
}
55、简易网页控制器,可替代webview
首先导入头文件#import <SafariServices/SafariServices.h>
遵守代理协议<SFSafariViewControllerDelegate>
SFSafariViewController *safari = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:@"http://www.jianshu.com/subscriptions#/timeline"]];
safari.delegate = self;
[self.navigationController pushViewController:safari animated:YES];
56、多种系统字体
for (NSString * family in [UIFont familyNames]) {
NSLog(@"familyNames:%@", family);
for (NSString * name in [UIFont fontNamesForFamilyName:family]) {
NSLog(@" name: %@",name);
}
}
57、禁止单个页面的屏幕滑动返回
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
// 禁用返回手势
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]){
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
}
- (void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]){
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
}
}
58、占位
59、关于使用cocoaPods,import导入时第三方库头文件没有提示问题的解决办法
选择target(就是左边你的工程target)—— BuildSettings
—— search Paths 下的 User Header Search Paths
双击后面的空白区域:点击“+”号添加一项:并且输入:“$(PODS_ROOT)”(没有引号),
选择:recursive(会在相应的目录递归搜索文件)
60、当系统版本大于10.3时,可以用系统的评分系统
#import <StoreKit/StoreKit.h>
[SKStoreReviewController requestReview];
61、数组的快速枚举 (注意:快速枚举里面不能对数组或字典进行任何修改,但是普通for循环可以)
[arr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
}];
[self.view.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[obj removeFromSuperview];
}];
[self.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[obj removeFromSuperview];
}];
[self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
62、push和present方法调用先后顺序
push
1、调用 A 的 viewWillDisappear 方法,
2、调用 B 的 viewWillAppear 方法
3、调用 A 的 viewDidDisappear 方法
4、调用 B 的 viewDidAppear 方法
present
1、调用 A 的 viewWillDisappear 方法,
2、调用 C 的 viewWillAppear 方法
3、调用 C 的 viewDidAppear 方法
4、调用 A 的 viewDidDisappear 方法
63、占位
64、如果控制器已经加载过,就不用再次加载,优化性能
if (self.viewLoaded) return;
65、NS_REQUIRES_SUPER用法
场景需求:在继承中,凡是要求子类重写父类的方法必须先调用父类的这个方法进行初始化操作;建议:父类的方法名后面加上NS_REQUIRES_SUPER; 子类重写这个方法就会自动警告提示要调用这个super方法,示例代码
// 注意:父类中的方法加`NS_REQUIRES_SUPER`,子类重写才有警告提示
- (void)prepare NS_REQUIRES_SUPER;
66、忽略警告
忽略未使用的变量
#pragma clang diagnostic push
#pragma clang diagnostic ignored "警告标识符"
//在这里写没有用到的声明
#pragma clang diagnostic pop
忽略所有警告
在 Build Settings 中找到 Custom Compiler Flags,双击 Other Warning Flags(可以配置 Debug 和 Release 环境),填入 -Wno-unused-variable,完成后,编译项目,项目中所有的此类型警告都没有了。这里所填写的内容规则,仅仅是在第一种方法中找到的警告标识符中的 W 字母后面加上no- 就可以了。
CocoaPods 导入第三方库忽略警告
通过 CocoaPods 给项目导入了一些第三方库,这些库里面或多或少会有些警告,想消除这些警告,很简单,只需在 Podfile 中加上这一句 inhibit_all_warnings!,所有通过 CocoaPods 安装的第三库的警告就没有了。
67、获取所有的私有权限
Privacy - Media Library Usage Description 使用媒体资源库
Privacy - Calendars Usage Description 使用日历
Privacy - Motion Usage Description 使用蓝牙
Privacy - Camera Usage Description --->App需要您的同意,才能访问运动与健身(运动使用)
Privacy - Health Update Usage Description 使用健康更新
Privacy - Microphone Usage Description 使用麦克风
Privacy - Bluetooth Peripheral Usage Description --->App需要您的同意,才能访问蓝牙
Privacy - Health Share Usage Description 使用健康分享
Privacy - Reminders Usage Description 使用提醒事项
Privacy - Location Usage Description 使用位置
Privacy - Location Always Usage Description 始终访问位置
Privacy - Photo Library Usage Description 访问相册
Privacy - Speech Recognition Usage Description 使用语音识别
Privacy - Location When In Use Usage Description 使用期间访问位置
Privacy - HomeKit Usage Description 沟通和控制家庭自动化配件
Privacy - Contacts Usage Description --> 通讯录权限
Privacy - NSSiriUsageDescription --> Siri的权限
Privacy - Music Usage Description --> 音乐
Privacy - TV Provider Usage Description --> 电视供应商使用权限
Privacy - Video Subscriber Account Usage Description --> 视频用户账号使用权限
68、占位
69、删除导航控制器栈中的某个控制器
//使用情况:假如控制器Apush到控制器B再push到控制器C,然后手势直接从控制器C返回到控制器A,这就需要从栈中移除掉控制器B
//得到当前视图控制器中的所有控制器
NSMutableArray *array = [self.navigationController.viewControllers mutableCopy];
//把B从里面删除
[array removeObjectAtIndex:1];
//把删除后的控制器数组再次赋值
[self.navigationController setViewControllers:[array copy] animated:YES];
70、和区域 点 尺寸相关
if (CGRectEqualToRect(rect1, rect2)) {
// 两个区域相等
}
if (CGPointEqualToPoint(point1, point2)) {
// 两个点相等
}
if (CGSizeEqualToSize(size1, size2)) {
// 两个size相等
}
if (CGRectIntersectsRect(rect1, rect2)) {
//两个rect是否有交叉
}
if(CGRectContainsRect(rect1, rect2)){
//rect1包含rect2
}
if(CGRectContainsPoint(rect, point)){
//rect的范围包含点point
}
if(CGRectIsEmpty(rect)){
//rect的宽和高为0
}
CGRectGetHeight(rect)//返回rect的高度
CGRectGetWidth(rect)//返回rect的宽度
CGRectGetMaxY(rect)//返回rect最底端的y值
CGRectGetMinY(rect);//返回rect最顶端的y值
CGRectGetMaxX(rect)//返回rect最右端的x值
CGRectGetMinX(rect);//返回rect最左端的x值
CGRectGetMidY(rect)//返回rect中心点的y值
CGRectGetMidX(rect)//返回rect中心点的x值
71、UIView 及其子类的切圆角时,要保证避免出现离屏渲染。
UIView(不包括其子类)
view.layer.cornerRadius = 3.f;
// 以下两行,任写一行
view.layer.masksToBounds = NO;
view.clipToBounds = NO;
// 以下两行,千万不要加!
view.layer.masksToBounds = YES;
view.clipToBounds = YES;
//UIView 只要设置图层的 cornerRadius 属性即可,如果设置 layer.masksToBounds = YES,会造成不必要的离屏渲染。
UITextField(两种实现方法)
// 天然支持设置圆角边框
textField.borderStyle = UITextBorderStyleRoundedRect;
// 与 UIView 类似
textField.layer.cornerRadius = cornerRadius;
UITextView(与 UIView 类似)
textView.layer.cornerRadius = cornerRadius;
UILabel
// 重点在此!!设置视图的图层背景色,千万不要直接设置 label.backgroundColor
label.layer.backgroundColor = [UIColor grayColor].CGColor;
label.layer.cornerRadius = cornerRadius;
UIButton(背景图片绘制方法)
+ (UIImage *)pureColorImageWithSize:(CGSize)size color:(UIColor *)color cornRadius:(CGFloat)cornRadius {
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, size.width, size.height)];
view.backgroundColor = color;
view.layer.cornerRadius = cornerRadius;
// 下面方法,第一个参数表示区域大小。第二个参数表示是否是非透明的。如果需要显示半透明效果,需要传NO,否则传YES。第三个参数是屏幕密度
UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, [UIScreen mainScreen].scale);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
UIImageView
* 贝塞尔曲线切割圆角
- (UIImageView *)roundedRectImageViewWithCornerRadius:(CGFloat)cornerRadius {
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:cornerRadius];
CAShapeLayer *layer = [CAShapeLayer layer];
layer.path = bezierPath.CGPath;
self.layer.mask = layer;
return self;
}
72、放置多行间距相同的UILabel
//总数
int sumCount = 10;
//每一行的数
int Count = 4;
CGFloat width = (self.view.frame.size.width- 100)/Count;
for (int i = 0; i < sumCount; i++) {
CGFloat y = 300 + i / Count * 50;
int loc = i % Count;
CGFloat x = 20 + (20 + width) * loc;
UILabel *lab = [[UILabel alloc]initWithFrame:CGRectMake(x, y , width, 30)];
lab.textAlignment = NSTextAlignmentCenter;
lab.text = [NSString stringWithFormat:@"%d",i];
lab.layer.borderColor = [UIColor redColor].CGColor;
lab.layer.borderWidth = 1;
lab.layer.masksToBounds = YES;
lab.layer.cornerRadius = 10;
[self.view addSubview:lab];
}
还有一种方式,两个 for 循环嵌套
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.backgroundColor = [UIColor groupTableViewBackgroundColor];
[btn setTitle:[NSString stringWithFormat:@"%d", i + (3 * j) + 1] forState:UIControlStateNormal];
[btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
btn.tag = (i + (3 * j) + 1) + 100;
btn.frame = CGRectMake(20 + i * 120, 20 + j * 70, 100, 50);
[self.view addSubview:btn];
}
}
73、同时重写了get和set方法会怎么样
同时重写了get和set方法之后@property默认生成的@synthesize就不会起作用了
这也就意味着你的类不会自动生成出来实例变量了
你就必须要自己声明实例变量
@interface ViewContaoller{ Nsstring *_name }
74、占位
75、设置动画和过渡期间应设置忽略触摸和其他活动(屏蔽 触发事件)
//开始屏蔽
[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
//结束屏蔽
[[UIApplication sharedApplication] endIgnoringInteractionEvents];
76、关于指针
a) 一个整型 int a;
b) 一个指向整型数的指针 int *a;
c) 一个指向指针的的指针,它指向的指针是指向一个整型数 int **a;
d) 一个有10 个整型数的数组 int a[10];
e) 一个有10 个指针的数组,该指针是指向一个整型数的 int *a[10];
f) 一个指向有10 个整型数数组的指针 int (*a)[10];
g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数 int (*a)(int);
h) 一个有10 个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数 int (*a[10])(int);
区别
int a = 15;
//*p 表示获取地址上的数据
int *p = &a;
printf("%d--%d",a,*p);
//a需要一次运算就能取得数据,而*p需要经过两次运算,多了一层间接.
//使用*p要先通过地址获取p本身的值,这个值是变量a的地址,在通过这个地址获取a的数据,但是使用a的话可以直接使用地址获取到数据
//使用指针是间接获取数据,使用变量名是直接获取数据,前者比后者的代价更高
77、void * 的作用
// void * a = "hello";
// void * b = 2;
// void * c = false;
由此得出void * 和id功能相同,表示万能指针
78、空
nil 表示对象为空
Nil表示类为空
NULL是C语言的,表示一个值为空
NSNotFound表示一个整数不存在,其实表示一个整数的最大值(NSIntegerMax)
79、占位
80、系统约束
[self.view addSubview:self.myTest1];
self.myTest1.translatesAutoresizingMaskIntoConstraints = NO;
//距离父视图上下左右个50,
[self.myTest1.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:50].active = YES;
[self.myTest1.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-50].active = YES;
[self.myTest1.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:50].active = YES;
[self.myTest1.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:-50].active = YES;
//[self.myTest1.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = YES;
//[self.myTest1.heightAnchor constraintEqualToConstant:45].active = YES;
//[self.myTest1.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES;
//[self.myTest1.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES;
81、占位
82、frame和bounds区别
frame:决定一个视图在它父视图上的显示区域和大小,以父视图左上角为原点(0,0).
bounds:以自己左上角为原点(0,0),并可以设置自身尺寸大小,决定了本地坐标系统的位置和大小.
bounds的有以下两个特点:
1. 它可以修改自己坐标系的原点位置,影响“子view”的显示位置。
2. 它可以通过改变宽高,改变自身的frame,进而影响到在父视图的显示位置和大小。
子视图的frame = 父视图的bounds的意义是子视图充满父视图.
83、视频播放器
//导入框架
#import <AVFoundation/AVFoundation.h>
#import <AVKit/AVKit.h>
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
AVPlayerViewController *vc = [AVPlayerViewController new];
AVPlayer *player = [AVPlayer playerWithURL:[NSURL URLWithString:@""]];
vc.player = player;
[self presentViewController:vc animated:YES completion:nil];
[vc.player play];
84、UIViewContentMode类型
UIViewContentModeScaleAspectFit, //这个图片都会在view里面显示,并且比例不变 这就是说 如果图片和view的比例不一样 就会有留白;
UIViewContentModeScaleAspectFill, // 这是整个view会被图片填满,图片比例不变 ,这样图片显示就会大于view;
UIViewContentModeRedraw这个选项是单视图的尺寸位置发生变化的时候通过调用setNeedsDisplay方法来重新显示。
UIViewContentModeCenter保持图片原比例在视图中间显示图片内容,如果视图大小小于图片的尺寸,则图片会超出视图边界
UIViewContentModeTop保持图片原比例在视图中间顶部显示图片内容
UIViewContentModeBottom保持图片原比例在视图中间底部显示图片内容
UIViewContentModeLeft保持图片原比例在视图中间左边显示图片内容
UIViewContentModeRight保持图片原比例在视图中间右边显示图片内容
UIViewContentModeTopLeft保持图片原比例在视图左上角显示图片内容
UIViewContentModeTopRight保持图片原比例在视图右上角显示图片内容
UIViewContentModeBottomLeft保持图片原比例在视图左下角显示图片内容
UIViewContentModeBottomRight保持图片原比例在视图右下角显示图片内容
85、在低版本Xcode上运行高版本的iOS真机设备
真机运行的支持包的位置位于:Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport
找到该文件后会看到很多支持真机运行的支持包,每个文件夹都是对应的iPhone系统。将从别人那里获取的支持包放到该文件路径下即可
86、输入框三种方式检测输入内容变化
1>通过UIControl
[textfield addTarget:self action:@selector(textChange:) forControlEvents:UIControlEventEditingChanged];
2>通过代理方法
textfield.delegate = self;
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
3>通过通知
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(AAAAAA) name:UITextFieldTextDidChangeNotification object:nil];
87、占位
88、占位
89、汉字转拼音
- (NSString *)firstCharactor:(NSString *)aString
{
//转成了可变字符串
NSMutableString *str = [NSMutableString stringWithString:aString];
//先转换为带声调的拼音
CFStringTransform((CFMutableStringRef)str,NULL, kCFStringTransformMandarinLatin,NO);
//再转换为不带声调的拼音
CFStringTransform((CFMutableStringRef)str,NULL, kCFStringTransformStripDiacritics,NO);
//转化为大写拼音
NSString *pinYin = [str capitalizedString];
//获取并返回首字母
return [pinYin substringToIndex:1];
}
90、常用的LLDB命令
help 列出所有命令
help <commond>列出某个命令更多细节,例如help print
print打印需要查看的变量,例如print number,简写为p,当后面是对象时则打印对象的地址.
po(print object)可以打印对象的description方法的结果,例如po array
expression可以改变一个值(动态改变执行内容),简写e
thread backtrace:作用是将线程的堆栈打印出来,简写为bt,加all可打印所有thread的堆栈
call 在调试器中直接更新UI(只在不需要显示输出,或是方法无返回值时使用call),例如call view.backgroundColor = UIColor.blue
n 断点指针执行到下一步
exit/quit 推出调试器
91、一种新的封装方式
//num 为最后一个数字
int num = (3,5);
//sum为三个数的和
int sum = ({
int a = 1;
int b = 2;
int c = 3;
a+b+c;
});
用这样的方式可以用来分装,其作用等于创建一个方法,返回自己需要的对象
92、占位
93、透过UIView
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
if (!self.passthroughTouches) { // 是否可以透过view
return [super pointInside:point withEvent:event];
}
for (UIView *subview in self.subviews) {
if (subview.isHidden) {
continue;
}
CGPoint subviewPoint = [self convertPoint:point toView:subview];
if ([subview pointInside:subviewPoint withEvent:event]) {
return YES;
}
}
return NO;
}
94、class、superclass、super、self含义
class:获取方法调用者的类名;
superclass:获取方法调用者的父类类名;
super:编译修饰符,不是指针,跟const类似于关键字的作用,指向父类的标志;
本质还是拿到当前对象去掉用父类的方法;
self:是一个指针,有地址;
95、UIColor 获取 RGB 值
UIColor *color = [UIColor colorWithRed:0.0 green:0.0 blue:1.0 alpha:1.0];
const CGFloat *components = CGColorGetComponents(color.CGColor);
NSLog(@"Red: %f", components[0]);
NSLog(@"Green: %f", components[1]);
NSLog(@"Blue: %f", components[2]);
NSLog(@"Alpha: %f", components[3]);
96、求两点间的距离
static __inline__ CGFloat CGPointDistanceBetweenTwoPoints(CGPoint point1, CGPoint point2) {
CGFloat dx = point2.x - point1.x;
CGFloat dy = point2.y - point1.y;
return sqrt(dx*dx + dy*dy);
}
97、获取某个view所在的控制器
- (UIViewController *)viewController {
UIViewController *viewController = nil;
UIResponder *next = self.nextResponder;
while (next) {
if ([next isKindOfClass:[UIViewController class]]) {
viewController = (UIViewController *)next;
break;
}
next = next.nextResponder;
}
return viewController;
}
98、字符串反转
第一种:
- (NSString *)reverseWordsInString:(NSString *)str {
NSMutableString *newString = [[NSMutableString alloc] initWithCapacity:str.length];
for (NSInteger i = str.length - 1; i >= 0 ; i --) {
unichar ch = [str characterAtIndex:i];
[newString appendFormat:@"%c", ch];
}
return newString;
}
//第二种:
- (NSString*)reverseWordsInString:(NSString*)str {
NSMutableString *reverString = [NSMutableString stringWithCapacity:str.length];
[str enumerateSubstringsInRange:NSMakeRange(0, str.length) options:NSStringEnumerationReverse | NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
[reverString appendString:substring];
}];
return reverString;
}
99、iOS 获取汉字的拼音
- (NSString *)transform:(NSString *)chinese {
//将NSString装换成NSMutableString
NSMutableString *pinyin = [chinese mutableCopy];
//将汉字转换为拼音(带音标)
CFStringTransform((__bridge CFMutableStringRef)pinyin, NULL, kCFStringTransformMandarinLatin, NO);
NSLog(@"%@", pinyin);
//去掉拼音的音标
CFStringTransform((__bridge CFMutableStringRef)pinyin, NULL, kCFStringTransformStripCombiningMarks, NO);
NSLog(@"%@", pinyin);
//返回最近结果
return pinyin;
}
100、判断view是不是指定视图的子视图
BOOL isView = [textView isDescendantOfView:self.view];
101、字符串中是否含有中文
- (BOOL)checkIsChinese:(NSString *)string {
for (int i=0; i<string.length; i++) {
unichar ch = [string characterAtIndex:i];
if (0x4E00 <= ch && ch <= 0x9FA5) {
return YES;
}
}
return NO;
}
102、UITextField每四位加一个空格,实现代理
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
// 四位加一个空格
if ([string isEqualToString:@""]) {
// 删除字符
if ((textField.text.length - 2) % 5 == 0) {
textField.text = [textField.text substringToIndex:textField.text.length - 1];
}
return YES;
} else {
if (textField.text.length % 5 == 0) {
textField.text = [NSString stringWithFormat:@"%@ ", textField.text];
}
}
return YES;
}
103、超出父视图范围的控件部分响应事件
-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
UIView* hitView = [super hitTest:point withEvent:event];
if (!hitView) {
CGPoint tempPoint = [_testBtn convertPoint:point fromView:self];
if (CGRectContainsPoint(_testBtn.bounds, tempPoint)) {
hitView = _testBtn;
}
}
return hitView;
}
104、如何做到对外只读、对内读写
//.h中
@property (readonly, nonatomic, strong, nullable) NSURL *baseURL;
//.m中
@property (readwrite, nonatomic, strong) NSURL *baseURL;