• IOS开发基础知识--碎片45


    1:iOS SEL的简单总结

    SEL就是对方法的一种包装。包装的SEL类型数据它对应相应的方法地址,找到方法地址就可以调用方法

    a.方法的存储位置

    在内存中每个类的方法都存储在类对象中

    每个方法都有一个与之对应的SEL类型的数据

    根据一个SEL数据就可以找到对应的方法地址,进而调用方法

    SEL类型的定义:  typedef struct objc_selector *SEL

     

    b.SEL对象的创建

     SEL s1 = @selector(test1);   // 将test1方法包装成SEL对象 

     SEL s2 = NSSelectorFromString(@"test1");   // 将一个字符串方法转换成为SEL对象

     

    c.SEL对象的其他用法

    // 将SEL对象转换为NSString对象  

    NSString *str = NSStringFromSelector(@selector(test));

     

    实例:

    Person *p = [Person new];
    
    // 调用对象p的test方法
    
    [p performSelector:@selector(test)];
    
    [person performSelector:@selector(test2:) withObject:@"传入参数"];
    Person类代码:
    
    #import "Person.h"
    @implementation Person
    - (void)test
    {
        NSLog(@"无参数的对象方法");
    }
    - (void)test2:(NSString *)str
    {
        NSLog(@"带有参数的方法%@",str);
    }
    @end

    d:在数组中的运用

    // 对一个数组array的每个元素执行一次test方法
    
    [array makeObjectsPerformSelector:@selector(test)];
    
    [array makeObjectsPerformSelector:@selector(test)  withObject:@"aaa"];
    //对一个数组array进行排序
    
    [array sortedArrayUsingSelector:@selector(compare:)];

    e:关于Sel传参运用(target - action设计模式)

    Button中我们经常用下面进行事件增加代码:

    - (void)addTarget:(nullable id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;

    实例:

    #import <UIKit/UIKit.h>
    
    @interface TapView : UIView
    //目标
    @property(weak,nonatomic)id target;
    //行为
    @property(assign,nonatomic)SEL action;
    
    //自定义方法
    -(void)addCustomtarget:(id)target andAction:(SEL)action;
    
    @end
    #import "TapView.h"
    
    @implementation TapView
    
    //自定义方法
    -(void)addCustomtarget:(id)target andAction:(SEL)action{
        _action = action;
        _target = target;
    }
    
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        //当视图点击的时候,target去执行action的方法并把自己传过去.
        //首先代理不能是空,而且代理(代理是对象!)的类中有方法并且能传出过来.
        if (nil != _target && [[_target class] instancesRespondToSelector:_action]) {
            [_target performSelector:_action withObject:self];
        }
    }

     另一个实例:

    #import <Foundation/Foundation.h>
    #import <objc/runtime.h>
    #import "Debug.h" // not given; just an assert
    
    @interface NSObject (Extras)
    
    // Enforce the rule that the selector used must return void.
    - (void) performVoidReturnSelector:(SEL)aSelector withObject:(id)object;
    - (void) performVoidReturnSelector:(SEL)aSelector;
    
    @end
    
    @implementation NSObject (Extras)
    
    // Apparently the reason the regular performSelect gives a compile time warning is that the system doesn't know the return type. I'm going to (a) make sure that the return type is void, and (b) disable this warning
    // See http://stackoverflow.com/questions/7017281/performselector-may-cause-a-leak-because-its-selector-is-unknown
    
    - (void) checkSelector:(SEL)aSelector {
        // See http://stackoverflow.com/questions/14602854/objective-c-is-there-a-way-to-check-a-selector-return-value
        Method m = class_getInstanceMethod([self class], aSelector);
        char type[128];
        method_getReturnType(m, type, sizeof(type));
    
        NSString *message = [[NSString alloc] initWithFormat:@"NSObject+Extras.performVoidReturnSelector: %@.%@ selector (type: %s)", [self class], NSStringFromSelector(aSelector), type];
        NSLog(@"%@", message);
    
        if (type[0] != 'v') {
            message = [[NSString alloc] initWithFormat:@"%@ was not void", message];
            [Debug assertTrue:FALSE withMessage:message];
        }
    }
    
    - (void) performVoidReturnSelector:(SEL)aSelector withObject:(id)object {
        [self checkSelector:aSelector];
    
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        // Since the selector (aSelector) is returning void, it doesn't make sense to try to obtain the return result of performSelector. In fact, if we do, it crashes the app.
        [self performSelector: aSelector withObject: object];
    #pragma clang diagnostic pop    
    }
    
    - (void) performVoidReturnSelector:(SEL)aSelector {
        [self checkSelector:aSelector];
    
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        [self performSelector: aSelector];
    #pragma clang diagnostic pop
    }
    
    @end

    2:代理模式实例

    #import <UIKit/UIKit.h>
    
    @protocol TouchViewDelegate <NSObject>
    -(void)changeViewColor:(UIColor *)color;
    @end
    
    
    @interface TouchView : UIView
    //声明一个代理,这个代理遵守TouchViewDelegate协议,
    @property(nonatomic,assign)id<TouchViewDelegate> delegate;
    @end
    #import "TouchView.h"
    
    @implementation TouchView
    
    //我们还是用touchesBegandian
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
        if (nil != self.delegate && [self.delegate respondsToSelector:@selector(changeViewColor:)]) {
            //我们传一个颜色到我们的ViewController去.
            [self.delegate changeViewColor:[UIColor brownColor]];
        }
    }
    
    @end
    运用代码:
    
    #import "ViewController.h"
    #import "TouchView.h"
    
    //在这里ViewController 要遵守协议....
    @interface ViewController ()<TouchViewDelegate>
    
    @property(nonatomic,strong)TouchView *touchView;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
    
        [super viewDidLoad];
    
        self.touchView = [[TouchView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
    
        self.touchView.backgroundColor = [UIColor redColor];
        //指定touchView的代理为ViewController.即为本身~
        self.touchView.delegate =self;
    
        [self.view addSubview: self.touchView];
    }
    
    -(void)changeViewColor:(UIColor *)color{
        //现在参数color是有值的,这是因为在TouchView那个页面传过来的.
        self.touchView.backgroundColor = color;
    }
    @end

    3:关于Bolck运用

    #import <UIKit/UIKit.h>
    
    //给block改名成MyBlock
    typedef void(^MyBlock)(NSString *);
    
    
    @interface OtherViewController : UIViewController
    
    //ARC:语义设置使用strong即可
    @property(nonatomic,strong)MyBlock block;
    
    @end
    #import "OtherViewController.h"
    
    @interface OtherViewController ()
    @property(nonatomic,strong)UITextField *textField;
    @end
    
    @implementation OtherViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.textField = [[UITextField alloc]initWithFrame:CGRectMake(0, 100, 414, 40)];
        self.textField.backgroundColor = [UIColor lightGrayColor];
        self.view.backgroundColor = [UIColor whiteColor];
        [self.view addSubview: self.textField];
    }
    
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        self.block(_textField.text);
        [self.navigationController popViewControllerAnimated:YES];
    }
    @end
    运用代码:
    
        OtherViewController *otherVC = [[OtherViewController alloc]init];
        __weak typeof(self)weak = self;
        //给block赋值~
        otherVC.block = ^(NSString *string){
            weak.label.text = string;
        };
    
        [self.navigationController pushViewController:otherVC animated:YES];

    4:UIButton的几种触发方式

    a、UIControlEventTouchDown 

      指鼠标左键按下(注:只是“按下”)的动作

    b、UIControlEventTouchDownRepeat

      指鼠标左键连续多次重复按下(注:只是“按下”)的动作,比如,鼠标连续双击、三击、……、多次连击。

      说明:多次重复按下时,事件序列是这样的:

      UIControlEventTouchDown -> 

      (UIControlEventTouchUpInside) -> 

      UIControlEventTouchDown -> 

      UIControlEventTouchDownRepeat -> 

      (UIControlEventTouchUpInside) -> 

      UIControlEventTouchDown -> 

      UIControlEventTouchDownRepeat -> 

      (UIControlEventTouchUpInside) ->

      ......

      除了第一次按下外,后面每次摁下都是一个UIControlEventTouchDown事件,然后紧跟一个UIControlEventTouchDownRepeat事件。

    cUIControlEventTouchDragInside

      指按下鼠标,然后在控件边界范围内拖动。

    dUIControlEventTouchDragOutside

      与UIControlEventTouchDragInside不同的是,拖动时,鼠标位于控件边界范围之外。

      但首先得有个UIControlEventTouchDown事件,然后接一个UIControlEventTouchDragInside事件,再接一个UIControlEventTouchDragExit事件,这时,鼠标已经位于控件外了,继续拖动就是UIControlEventTouchDragOutside事件了。

      具体操作是:在控件里面按下鼠标,然后拖动到控件之外。

    eUIControlEventTouchDragEnter

      指拖动动作中,从控件边界外到内时产生的事件。

    fUIControlEventTouchDragExit

      指拖动动作中,从控件边界内到外时产生的事件。

    gUIControlEventTouchUpInside

      指鼠标在控件范围内抬起,前提先得按下,即UIControlEventTouchDownUIControlEventTouchDownRepeat事件。

    hUIControlEventTouchUpOutside

      指鼠标在控件边界范围外抬起,前提先得按下,然后拖动到控件外,即 

      UIControlEventTouchDown -> 

      UIControlEventTouchDragInside(n ) -> 

      UIControlEventTouchDragExit -> 

      UIControlEventTouchDragOutside(n 

      时间序列,再然后就是抬起鼠标,产生UIControlEventTouchUpOutside事件。

     

    5:让编译器对一些警告闭嘴

    a:方法弃用告警

    #pragma clang diagnostic push  
      
    #pragma clang diagnostic ignored "-Wdeprecated-declarations"      
    //会报警告的方法,比如SEL 
    [TestFlight setDeviceIdentifier:[[UIDevice currentDevice] uniqueIdentifier]];  
      
    #pragma clang diagnostic pop  

    b:未使用变量

    #pragma clang diagnostic push   
    #pragma clang diagnostic ignored "-Wunused-variable"   
        
    int a;   
    
    #pragma clang diagnostic pop 

     6:一个六边形,并只在六边形里面有点击效果

    #import <UIKit/UIKit.h>
    //六边形Button
    @interface HexagonButton : UIView
    NS_ASSUME_NONNULL_BEGIN
    
    typedef void (^HexagonButtonBlock)();
    
    @property (nonatomic, strong) UIBezierPath *path;
    @property (nonatomic, strong) CAShapeLayer *maskLayer;
    @property (nonatomic, strong) HexagonButtonBlock block; //点击事件
    
    //添加点击事件
    
    
    NS_ASSUME_NONNULL_END
    @end
    #import "HexagonButton.h"
    
    @implementation HexagonButton
    - (instancetype) initWithFrame:(CGRect)frame
    {
        if ([super initWithFrame:frame]) {
            
            self.backgroundColor = [UIColor brownColor];
            self.userInteractionEnabled = YES;
            
            //添加单击手势
            UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(click:)];
            [self addGestureRecognizer:tap];
        }
        return self;
    }
    - (void) layoutSubviews
    {
        [super layoutSubviews];
        CGFloat SIZE = self.frame.size.width;
        // step 1: 生成六边形路径
        CGFloat longSide = SIZE * 0.5 * cosf(M_PI * 30 / 180);
        CGFloat shortSide = SIZE * 0.5 * sin(M_PI * 30 / 180);
        CGFloat k = SIZE * 0.5 - longSide;  //路径整体下移,保证六边形路径位于图形中间
        
        _path = [UIBezierPath bezierPath];
        [_path moveToPoint:CGPointMake(0, longSide  + k)];
        [_path addLineToPoint:CGPointMake(shortSide, + k)];
        [_path addLineToPoint:CGPointMake(shortSide + shortSide + shortSide,  k)];
        [_path addLineToPoint:CGPointMake(SIZE, longSide + k)];
        [_path addLineToPoint:CGPointMake(shortSide * 3, longSide * 2 + k)];
        [_path addLineToPoint:CGPointMake(shortSide, longSide * 2 + k)];
        [_path closePath];
        
        // step 2: 根据路径生成蒙板
        _maskLayer = [CAShapeLayer layer];
        //    _maskLayer.position = self.center;
        _maskLayer.path = [_path CGPath];
        
        // step 3: 添加蒙版
        self.layer.mask = _maskLayer;
    
        self.backgroundColor = [UIColor orangeColor];
    }
    
    //点击事件
    - (void) click:(UITapGestureRecognizer *) tap
    {
        if (_block) {
            _block();
        }
    }
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
        //如果点击的区域在所创建的路径范围内
        if (CGPathContainsPoint(_path.CGPath, NULL, point, NO)) {
            return [super hitTest:point withEvent:event];
        }
        return nil;
    }
    
    @end
        //创建六变形按钮
        HexagonButton * hexagonButton = [[HexagonButton alloc] initWithFrame:CGRectMake(20, 20, 100, 100)];
        hexagonButton.center = self.view.center;
        hexagonButton.block = ^(){
            NSLog(@"六边形区域被点击");
        };
        [self.view addSubview:hexagonButton];

    7:self.navigationController.viewControllers修改

    var controllerArr = self.navigationController?.viewControllers//获取Controller数组
    controllerArr?.removeAll()//移除controllerArr中保存的历史路径
        //重新添加新的路径
    controllerArr?.append(self.navigationController?.viewControllers[0])
    controllerArr?.append(C)
    controllerArr?.append(B)
        //这时历史路径为(root -> c -> b)
        //将组建好的新的跳转路径 set进self.navigationController里
    self.navigationController?.setViewControllers(controllerArr!, animated: true)//直接写入,完成跳转B页面的同时修改了之前的跳转路径

    主要解决那些乱七八糟的转转,不按顺序来的问题;

  • 相关阅读:
    集合操作
    聚合函数
    图存储3-十字链表
    图存储2-邻接表
    图存储1 临接矩阵
    字符串逆序,字符串翻转
    读写文件
    加密算法
    静态变量-动态变量
    【Qt】UserDefindeControl
  • 原文地址:https://www.cnblogs.com/wujy/p/5732038.html
Copyright © 2020-2023  润新知