美文网首页将来跳槽用
iOS 知识点个人总结(不定期持续性更新)

iOS 知识点个人总结(不定期持续性更新)

作者: RWz_my | 来源:发表于2019-11-05 10:31 被阅读0次

    1.单个控制器监听进入后台

    在该控制器的-viewDidLoad方法中,添加代码监听notification,也可以使用监听APP返回方法

    [[NSNotificationCenter defaultCenter] addObserver:self

    selector:@selector(someMethod:)

    name:UIApplicationDidBecomeActiveNotification object:nil];

    监听方法的具体实现

    -(void)someMethod:(NSNotification *)noti

    {

            //从该控制器进入后台时需要执行的代码

    }

    恢复到前台

    - (void)applicationDidBecomeActive:(UIApplication *)application{

        NSLog(@"---applicationDidBecomeActive----");

    }


    2.十六进制字符串转换成字节数组.

    目标字符串 NSString *str = @"0200107580FD7590FD750FD7590FD75A0FD";

    调用方法:NSData *temp = [string hexToBytes];  转换后

     byte数组 Byte byteArr[] = { 0x02, 0x00, 0x10, ... ,  0xFD };

    3、对于项目中的第三库一定要进行再次封装,包括网络、刷新、提示、模型转换等所有能封装的部分,一直用MJExtension来做字典转模型,突然想用YYModel了,项目中替换很麻烦,刷新也一样,一直用第三方框架,突然想自己写,改起来麻烦的不要不要的;

    4、熟悉一下测试的几种方案,例如交叉测试(一个功能正在运行,另一个功能运行对它的影响,例如 扫码时打开灯光,突然退到后台,再回来查看,可能灯光已经熄灭,按钮还没改变状态)等,这样写程序时才知道往哪些方面考虑

    5、多写点代码块,写起代码来会很快,我把自定义Cell都封装了代码块,用xib布局cell就没有纯手写这么快了,改起来还麻烦,这就是代码块的好处;

    6、主控制器因为代码比较多,结构一定要清晰,才方便寻找,插入的类按 服务工具类+MVC 划分,属性按修饰符划分,下面代码按功能划分,如下

    #import "ViewController.h"

    // 工具和服务类

    #import "Header.h"

    #import "Tool1.h"

    #import "Tool2.h"

    // Model

    #import "Model1.h"

    #import "Model2.h"

    #import "Model3.h"

    // View

    #import "View1.h"

    #import "View2.h"

    #import "View3.h"

    // Controller

    #import "ViewController1.h"

    #import "ViewController2.h"

    #import "ViewController3.h"

    @interface ViewController ()

    // 按修饰符划分

    @property (nonatomic, assign) NSInteger num1;

    @property (nonatomic, assign) NSInteger num2;

    @property (nonatomic, strong, nonnull) NSMutableArray<NSString *> *object3;@property (nonatomic, strong, nonnull) NSMutableArray<NSNumber *> *object4;

    @property (nonatomic, copy, nullable) NSString *object5;

    @property (nonatomic, copy, nullable) NSString *object6;

    @property (nonatomic, weak) UILabel *object1;

    @property (nonatomic, weak) UILabel *object2;

    @end

    @implementation ViewController

    - (void)viewDidLoad {   

        [super viewDidLoad];    

    }

    #pragma mark - 初始化View

    - (void)initView{

     }

    #pragma mark - 系统方法,界面显示到销毁

    #pragma mark - 代理

    #pragma mark - 按钮点击,通知,定时器

    #pragma mark - 辅助方法#pragma mark - 懒加载

    @end

    7、定时器不是马上开始的,多久触发一次事件,多久才开始,记得在退出页面的时候释放定时器,否则控制器不会释放;

    8、如果错误提示中出现了duplicate这样的字眼,很可能就是引入了.m文件

    9、UIView的tag不能为0;

    10、字典转JSON字符串;

    NSData *data = [NSJSONSerialization dataWithJSONObject:params options:NSJSONWritingPrettyPrinted error:nil];

    NSString *paramStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

    11、有时在动画过程中,需要避免用户重复操作,否则很容易崩溃。

    建议动画过程中设置[[UIApplication sharedApplication] beginIgnoringInteractionEvents];

    允许用户操作[[UIApplication sharedApplication] endIgnoringInteractionEvents];


    12、如果延时执行事件会被多次触发,那是一件很危险的事情,需要取消前面的延时执行事件

    [selfperformSelector:<#(nonnull SEL)#>

    withObject:<#(nullable id)#>afterDelay:<#(NSTimeInterval)#>];// 延时执行

    [NSObject cancelPreviousPerformRequestsWithTarget:<#(nonnull id)#>

    selector:<#(nonnull SEL)#>object:<#(nullable id)#>]// 取消延时执行

    13、测试某部分代码的运行时间

    NSTimeInterval beginTime = CFAbsoluteTimeGetCurrent();

    ......// 执行代码

    NSTimeInterval endTime = CFAbsoluteTimeGetCurrent();

    time = endTime-beginTime;// 运行时间

    14、对某个控件截图

    UIGraphicsBeginImageContextWithOptions(view.bounds.size,NO,0);

    [view.layer renderInContext:UIGraphicsGetCurrentContext()];

    UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    15、添加毛玻璃效果

    UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];

    UIVisualEffectView *effectView = [[UIVisualEffectView alloc]initWithEffect:effect];

    effectView.contentView = 控件;

    16、添加长按手势,在手势开始时才执行方法,避免方法被调用两次

    - (void)longPress:(UILongPressGestureRecognizer *)longPressGesture{

        if (UIGestureRecognizerStateBegan != longPressGesture.state) {

            return;

        }

        ... // 执行方法

    }

    17、输入框有值时才能点击return key

    textField.enablesReturnKeyAutomatically = YES;

    18、isKindOfClass判断对象是否是一个类的成员,或者是派生自该类的成员isMemberOfClass确定对象是否是当前类的成员;


    19、tableView设置cell的分割线从屏幕左侧边缘开始

     cell.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0);

    20、tableView当内容不够时,去掉底部的分割线

    self.tableView.tableFooterView = [[UIView alloc]init];

    21、UITableView设置为Plain的样式时,你又有多组时,组头就会默认有悬浮效果,停留在上边,如果不想组头悬浮在上边,可以将样式设为Grouped,把足部设置很小,解决这问题;

    UITableView *tableView = [[UITableView alloc] initWithFrame:CGRectMake(x,y,w,h) style:UITableViewStyleGrouped];

    tableView.sectionFooterHeight = 0.0001;

    22、设置UITableViewCell之间的间距,在自定义cell中重写setFrame方法

    -(void)setFrame:(CGRect)frame{

        frame.origin.y += 5;

        frame.size.height -= 5;

        [super setFrame:frame];

    }

    23、修改UISearchController上searchBar的风格,遍历子控件(很有用),找到合适的, 设置想要的子控件的颜色和分格;

    UIImageView *barImageView = self.searchController.searchBar.subviews[0].subviews[0];

    barImageView.layer.borderColor = [UIColor lightGrayColor];

    barImageView.layer.borderWidth = 1;

    UIView *textView = self.searchController.searchBar.subviews[0].subviews[1];

    textView.backgroundColor = [UIColor whiteColor];

    24、监测WKWebView的加载进度

    [wkWebView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];

    25、一个控件获取在某个控件上的坐标点的四种方式

    // 获取View在window上的坐标点的四种写法

    // 使用 convertRect:toRect 方法

    CGRect rect = [view convertRect:view.bounds toRect:window];

    CGRect rect = [view.superView convertRect:view.frame toRect:window];

    // 使用 convertRect:from 方法

    CGRect rect = [window convertRect:view.boundsfrom:view];

    CGRect rect = [window convertRect:view.framefrom:view.superView];

    26、iOS11获取最上面的window

    // iOS 11 以前

    UIView *windowView = [[UIApplication sharedApplication].windows lastObject];

    // iOS 11 以后

    UIView *windowView = [[UIApplication sharedApplication].windows firstObject];

    27、某个控件有双击和单击时,设置双击失败时,才触发单击

    [oneTap requireGestureRecognizerToFail:doubleTap];

    28、设置图片捏合缩放,双击放大

    // 首先把imageView添加到scrollview中

    - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{

        return self.imageView;

        // 在代理返回当前imageView现

    }

    - (void)scrollViewDidZoom:(UIScrollView *)scrollView{

        // 保证绕着中心点缩放

            CGSize boundsSize = self.scrollView.bounds.size;

            CGRect frameToCenter = self.imageView.frame;

            if (frameToCenter.size.width < boundsSize.width) {

                frameToCenter.origin.x = floorf((boundsSize.width - frameToCenter.size.width) * 0.5f);

            } else {

                frameToCenter.origin.x = 0;

            }

            if (frameToCenter.size.height < boundsSize.height) {

                    frameToCenter.origin.y = floorf((boundsSize.height - frameToCenter.size.height) * 0.5f);

            }else {

                    frameToCenter.origin.y = 0;

            }

            if (!CGRectEqualToRect(self.imageView.frame, frameToCenter)) {

                    self.imageView.frame = frameToCenter;

            }

    }

    -(void)doubleTap:(UITapGestureRecognizer *)tapBgRecognizer{

        CGFloat scale = 4; // 最大缩放比例

        if (self.self.imageView.frame.frame.size.width < kScreenWidth * scale) {

            CGPoint point = [tapBgRecognizer locationInView:self.imageView.frame];

            CGFloat xSize = kScreenWidth / scale;

            CGFloat ySize = kScreenHeight / scale;

            CGRect zoomRect = CGRectMake(point.x - xSize * 0.5f, point.y - ySize * 0.5f, xSize, ySize);

            self.scrollView.maximumZoomScale = scale;

            // 以点击点为中心缩放到最大

            [self.scrollView zoomToRect:zoomRect animated:YES];

        } else {

            [UIView animateWithDuration:0.25 animations:^{

            self.scrollView.zoomScale = 1.0;

            self.scrollView.contentSize = self.scrollView.bounds.size;

            self.self.imageView.frame.frame = self.originFrame; }];

        }

    }

    29、寻找当前控件的控制器

    -(UIViewController*)ht_viewController{

        for(UIView *next = self; next;  next = next.superview){

            UIResponder *nextResponder = [next nextResponder];

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

                return (UIViewController *)nextResponder;

            }

        }

        return nil;

    }

    30、UITextField的inputView属性是指第一响应的不是键盘,而是赋值给inputView的那个view, inputAccessoryView 是指往键盘上添加另一个view;

    31、设置键盘在UIScrollView拖动动时消失

    scrollview.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag

    32、设置UITableViewCell之间的分割线颜色;

    self.tableView.separatorColor = [UIColor redColor];

    33、iOS9以后点击状态栏,UIScrollView可返回顶部;

    34、显示状态栏的网络请求菊花;

    // 显示菊花-----NO为关闭菊花

    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

    35、让UILabel的字体适应指定的宽度,当宽度大时,字体不变, 宽度小时, 字体变小适应宽度

    label.adjustsFontSizeToFitWidth = YES;

    36、监听拖动进度条时的状态

    监听拖动进度条时的状态

    [slider addTarget:self action:@selector(sliderChange:event:) forControlEvents:UIControlEventValueChanged];

    - (void)sliderChange:(UISlider *)slider event:(UIEvent *)event{

        UITouch *touch = [[event allTouches] anyObject];

        // 根据状态来做相应的事情,避免拖动时一直调用某些事件

        switch (touch.phase) {

            case UITouchPhaseBegan: // 开始

            case UITouchPhaseMoved: // 拖动

            case UITouchPhaseEnded: // 结束

            default:

                break;

            }

    }

    37、让UITableView的某一行滚到底部;

    [self.tableView scrollToRowAtIndexPath:indexPath    atScrollPosition:UITableViewScrollPositionBottom animated:YES];

    38、以Modal的形式push出一个界面;

    [UIView beginAnimations:nil context:NULL];

    [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];

    [UIView setAnimationDuration:0.75];

    [self.navigationController pushViewController:vc animated:NO];

    [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.navigationController.view cache:NO];

    [UIView commitAnimations];

    39、阻止设备自动锁屏[UIApplication sharedApplication].idleTimerDisabled = YES;在后台不管用,退出当前页面时,记得设为NO


    40、为了避免循环引用,在block中我们一般都用弱引用,但是block中的弱引用对象可能会提前释放,造成崩溃,我们需要在block中强引用一下这个弱对象;

    __weak __typeof(self)weakSelf = self;

    view.callback = ^(ViewStatus status) {

        // 强引用这个对象,避免执行到一半 self释放,造成崩溃;

        __strong __typeof(weakSelf)strongSelf = weakSelf;

        [strongSelf doSomething];

    }

    41、如果一个参数中需要包含多个枚举值,用NS_OPTIONS,不要用NS_ENUM

    // 位运算保证任意组合的枚举值进行或运算能得到唯一的值

    typedefNS_OPTIONS(NSUInteger,TestName){

            TestNameXiaoHua=1<<0,// 小花

            TestNameXiaoBai=1<<1,// 小白

            TestNameXiaoHei=1<<2// 小黑

    };

    [self eat:TestNameXiaoHua | TestNameXiaoBai];// 让小花和小白有饭吃;

    -(void)eat:(TestName)name{

        if( (name & TestNameXiaoHua) || (name & TestNameXiaoBai) ){

            NSLog(@"有饭吃");

        }

    }

    42、快速生成一个带值的可变字典

    NSMutableDictionary *mutDic = @{@"key":@"value"}.mutableCopy;

    43、忽略编译器警告

    #pragma clang diagnostic push

    #pragma clang diagnostic ignored "-Wgnu"    // 设置要忽略的类型 这里是GNU警告

    // 代码

    #pragma clang diagnostic pop

    44、为了避免多线程访问数据库,造成数据混乱,让读写方法都在同一个队列中进行;

    static const void * const IOKey = &IOKey;

    // 开辟一个单例队列

    dispatch_queue_t NTESDispatchIOQueue(){

        static dispatch_queue_t queue;

        static dispatch_once_t onceToken;

        dispatch_once(&onceToken, ^{

        // dispatch_queue_create("", DISPATCH_QUEUE_SERIAL) queue = dispatch_queue_create("io.queue", 0);

        dispatch_queue_set_specific(queue, IOKey, (void *)IOKey, NULL); // 设置队列的的标记 });

        return queue;

    }

    typedef void(^dispatch_block)(void);

    void io_sync_safe(dispatch_block block){

        // 如果是自己设置的队列,执行block

        if (dispatch_get_specific(IOKey)) {

            block();

        } else// 如果不是自己设置的队列,先创建队列,再执行block {

            dispatch_sync(NTESDispatchIOQueue(), ^() {

            block();

        });

    }

    45、监听UITextField值的改变,可以使用这个方法

    [_textViewaddTarget:self.action:@selector(textFieldDidChangeValue:)forControlEvents:UIControlEventEditingChanged]

    而不要使用这个代理,因为可能监听不到

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

    46、把C++算法库封装在OC文件里形成静态库时,记得把OC的.m文件改成.mm文件

    47、如果视图里面存在唯一一个UIScrollView或其子类View时,会主动设置相应的内边距,避免被导航栏遮住,如果我们的导航栏不透明,原点会从我们的导航栏下方算起,导致上方留白,解决这问题:

    if (@available(iOS 11.0, *)) {

            self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;        //UIScrollView也适用

    }else {

            self.automaticallyAdjustsScrollViewInsets = NO;

     }

    48、如果数组中的元素是唯一的,或者要查询某个数据是否在该数组中,不要使用NSArray, 而是使用集合NSSet,集合采用的是哈希表,查询速度更快;


    49、动画里的万能神器CAShapeLayer,性能特别好,能实现很多神奇的效果,做什么动画前优先考虑它,尤其做股票财经、健康APP类的,经常需要画图,如果遇到性能问题,试试它;


    50、swift中为了避免循环引用,我们使用weak或者unowned来解决,但它们是有区别的; unowned更像OC里的unsafe_unretained,当引用对象释放了以后,它仍然会保持对引用对象的一个无效引用,如果尝试调用方法和成员属性的话,程序就会崩溃;  weak则会在引用的内容被释放后,它会自动地变成 nil;  因此我们在使用它时,如果你引用对象不会释放, 使用unowned,写起来方便点;  如果你引用对象会被释放,请使用weak,例如网络请求;


    51、在swift中用强制解包!一定要非常小心,尽量少用,一不小心程序就崩溃了;


    52、在swift中数组和字典都属于值类型,相当于int类型,跟oc不一样,当你把数组赋值给另一个数组,修改数组的值不会影响另一个数组;


    53、__bridge 用于OC指针与c语言中的 void *互相转换,虽然 id 和void *能够相互转换。但转换为void *,其安全性与赋值给__unsafe_unretained修饰符相近,甚至会更低。如果管理时不注意赋值对象的所有者,就会因悬垂指针而导致程序崩溃。具体细节,参考 __bridge 的那些事儿


    54、void* 类型指针通用变体类型指针;可以不经转换,赋给其他指针,函数指针除外;malloc返回的就是void*类型。

    NULL指针:是一个标准规定的宏定义;#define NULL ((void *) 0)      用来表示空指针常量;

    零指针:指针值为0,零值指针,没有存储任何内存地址的指针;可以使任意一种指针类型,eg:void * ;int * ;double *;

    空指针:指针赋值为0;0*7;3-3等之后,指针即变成空指针;即:空指针不指向任何实际的对象或者函数;NULL指针和零指针都是空指针。

    野指针指向垃圾内存的指针;(1)指针变量没有初始化(2)指针被delete或者free之后没有置为空(3)指针操作超越了变量的范围

    悬垂指针:指向曾经存放对象的内存,但是该对象已经不存在了;delete操作完成后的指针就是悬垂指针,此时需要将指针置为0变为零值指针;

    55、WKWebView 与 JS 交互,需要添加 [userController addScriptMessageHandler:self name:@"callFunction"];  callFunction 可自定义,与 JS 保持一致,才可交互。

    于控制器中添加 evaluateJavaScript:方法


    56.关于 -> 语法 与 .语法

    self -> _topview 这个是把 self 当成了个结构体指针;

    self.topview 是把self 当成了一个对象,或者说是结构体变量;

    另外,self-> 不会触发 set方法,self. 会触发。

    . 左侧可以是结构体变量,也可以是对象;-> 左侧肯定是当成 结构体指针。

    像这种用法, k 就是个结构体变量,p 是取了k 的地址,所以p 是个 astrct 类型指针,他就可以用->

    成员变量 + 读写方法 = 类属性

    简单直接的理解方式:.语法是去访问类属性,->是访问成员变量。 . 语法用于寻址,在c 语言中,左侧必须是个类型变量。而 - > 用于间接寻址。比如下图

    验证上面所说

    第一行 &k 和 &(k.a)的地址完全一样,是因为在这个结构体中,于内存存储的时候,最开始的部分存放的就是a,然后紧接着就是b,当拿到这个结构题类型的变量K, 实际上就是拿到存储的首地址。

    而第二行的 p ,其实是 指针p 自身的地址,而指针指向的是 k。

    相关文章

      网友评论

        本文标题:iOS 知识点个人总结(不定期持续性更新)

        本文链接:https://www.haomeiwen.com/subject/bmfsbctx.html