iOS开发 UIAlertView与UIActionSheet替换方案之SDAlertView与SDActionSheet

iOS开发 UIAlertView与UIActionSheet替换方案之SDAlertView与SDActionSheet

由于在iOS开发中,项目中还在使用UIAlertView与UIActionSheet,由于这两个类在iOS开始废弃

UIKIT_EXTERN API_DEPRECATED(“UIAlertView is deprecated. Use UIAlertController with a preferredStyle of UIAlertControllerStyleAlert instead”, ios(2.0, 9.0)) API_UNAVAILABLE(tvos) API_UNAVAILABLE(visionos, watchos) NS_SWIFT_UI_ACTOR

需要更换成UIAlertController。UIAlertView与UIActionSheet都更换成UIAlertController,一个一个文件更改代码不太合适,更改较多,所以考虑自定义类封装UIAlertController使用。

UIAlertView与UIActionSheet

一般在UIAlertView中,我们会使用initWithTitle方法进行初始化

  • (instancetype)initWithTitle:(nullable NSString )title message:(nullable NSString )message delegate:(nullable id //)delegate cancelButtonTitle:(nullable NSString *)cancelButtonTitle otherButtonTitles:(nullable NSString *)otherButtonTitles, … NS_REQUIRES_NIL_TERMINATION;

然后使用其代理方法UIAlertViewDelegate的方法

  • (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex API_DEPRECATED(“Use UIAlertController instead.”, ios(2.0, 9.0)) API_UNAVAILABLE(visionos, watchos);
    在该方法处理点击事件。

UIActionSheet和UIAlertView使用方式类似。

封装UIAlertController

在工程中直接替换会更改太多,那这时候我这边考虑封装UIAlertController进行,封装后的类SDAlertView
虽然类名SDAlertView,但是其实继承NSObject,其中封装UIAlertController进行使用。

  • 初始化方法initWithTitle
- (instancetype)initWithTitle:(NSString *)title message:(NSString *)message delegate:(id)delegate cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION;
  • 创建delegate及新增方法

@protocol SDAlertViewDelegate <NSObject>

- (void)alertView:(SDAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex;

@end

  • show方法
通过获取keyWindow的rootViewController来展示UIAlertController

完整代码如下
SDAlertView.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "UIAlertAction+SDIndex.h"

@protocol SDAlertViewDelegate;
@interface SDAlertView : NSObject

@property (nonatomic, weak) id<SDAlertViewDelegate>delegate;

@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *message;   // secondary explanation text
@property (nonatomic) NSInteger tag;                // default is 0

- (instancetype)initWithTitle:(NSString *)title message:(NSString *)message delegate:(id)delegate cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION;

- (NSString *)buttonTitleAtIndex:(NSInteger)buttonIndex;

- (void)show;

@end


@protocol SDAlertViewDelegate <NSObject>

- (void)alertView:(SDAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex;

@end

SDAlertView.m

#import "SDAlertView.h"

@interface SDAlertView ()

@property (nonatomic, copy) NSString *cancelButtonTitle;
@property (nonatomic, copy) NSArray *otherButtonTitleList;
@property (nonatomic, copy) NSArray *allBtnTitleList;

@property (nonatomic, strong) UIAlertController *alertController;

@end

@implementation SDAlertView

- (instancetype)init
{
    self = [super init];
    if (self) {
        if (sd_alertSheets == nil) {
            sd_alertSheets = [NSMutableArray arrayWithCapacity:0];
        }
    }
    return self;
}

- (instancetype)initWithTitle:(NSString *)title message:(NSString *)message delegate:(id)delegate cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION; {
    self = [self init];
    if (self) {
        self.delegate = delegate;
        self.title = title;
        self.message = message;
        self.cancelButtonTitle = cancelButtonTitle;
        NSMutableArray *tmpTitleList = [NSMutableArray arrayWithCapacity:0];
        if (otherButtonTitles) {
            [tmpTitleList addObject:otherButtonTitles];
            
            // 后面的不定参数,可以使用va_list来获取
            //va_list 是一个指针变量  本质上是一个指针
            va_list arg_lists;
            //初始化 va_list
            va_start(arg_lists, otherButtonTitles);
            
            NSString * obj = nil;
            //va_arg(arg_lists, NSString*)用户来获取值
            while((obj=va_arg(arg_lists, NSString*))){
                if (obj && obj.length > 0) {
                    [tmpTitleList addObject:[NSString stringWithFormat:@"%@", obj]];
                }
            };
            //结束参数获取
            va_end(arg_lists);
        }
        
        
        self.otherButtonTitleList = [NSArray arrayWithArray:tmpTitleList];
        
        
        // 所有按钮title
        NSMutableArray *tmpAllTitles = [NSMutableArray arrayWithCapacity:0];
        if (self.cancelButtonTitle && [self.cancelButtonTitle isKindOfClass:[NSString class]] && self.cancelButtonTitle.length) {
            [tmpAllTitles addObject:self.cancelButtonTitle];
        }
        [tmpAllTitles addObjectsFromArray:self.otherButtonTitleList];
        self.allBtnTitleList = tmpAllTitles;
        
        // 初始化AlertController
        [self setupAlertView];
        
        // 采用这种方式,当点击的时候,将其从列表移除,防止在调用handleAlertAction时候self被释放掉了。
        // 调用handleAlertAction,将其从数组中移除,移除后自动调用dealloc方法
        [sd_alertSheets addObject:self];
        NSLog(@"sd_alertSheets:%@", sd_alertSheets);
    }
    return self;
}

- (void)setupAlertView {
    self.alertController = [UIAlertController alertControllerWithTitle:self.title
                                                                   message:self.message
                                                            preferredStyle:UIAlertControllerStyleAlert];
    
    __block BOOL hasCancelBtn = NO;
    __weak typeof(self) weakSelf = self;
    if (self.cancelButtonTitle && [self.cancelButtonTitle isKindOfClass:[NSString class]] && self.cancelButtonTitle.length) {
        hasCancelBtn = true;
        __block int buttonIndex = 0;
        UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:self.cancelButtonTitle
                                                               style:UIAlertActionStyleCancel
                                                             handler:^(UIAlertAction * _Nonnull action) {
            [weakSelf handleAlertAction:action buttonIndex:action.actionIndex];
        }];
        cancelAction.actionIndex = buttonIndex;
        [self.alertController addAction:cancelAction];
    }
    
    for (int i = 0; i < self.otherButtonTitleList.count; i++) {
        __block int buttonIndex = i + (hasCancelBtn?1:0);
        NSString *title = [self.otherButtonTitleList objectAtIndex:i];
        UIAlertAction *alertAction = [UIAlertAction actionWithTitle:title
                                                           style:UIAlertActionStyleDefault
                                                         handler:^(UIAlertAction * _Nonnull action) {
            [weakSelf handleAlertAction:action buttonIndex:action.actionIndex];
        }];
        alertAction.actionIndex = buttonIndex;
        [self.alertController addAction:alertAction];
    }
}

- (NSString *)buttonTitleAtIndex:(NSInteger)buttonIndex {
    if (self.allBtnTitleList && (buttonIndex < self.allBtnTitleList.count)) {
        NSString *title = [self.allBtnTitleList objectAtIndex:buttonIndex];
        return title;
    }
    return nil;
}

- (void)show {
    if (!self.alertController) {
        return;
    }
    
    UIViewController *topViewController = UIApplication sharedApplication].keyWindow.rootViewController;
    [topViewController presentViewController:self.alertController animated:YES completion:^{
        DLog(@"SDAlertView did show completion");
    }];
}

- (void)handleAlertAction:(UIAlertAction *)alertAction buttonIndex:(NSInteger)buttonIndex {
    DLog(@"handleAlertAction alertAction:%@ buttonIndex:%ld", alertAction, buttonIndex);
    if (self.delegate && [self.delegate respondsToSelector:@selector(alertView:clickedButtonAtIndex:)]) {
        [self.delegate alertView:self clickedButtonAtIndex:buttonIndex];
    }
    
    // 点击后再让其调用dealloc
    if ([sd_alertSheets containsObject:self]) {
        [sd_alertSheets removeObject:self];
    }
}

- (void)dealloc {
    DLog(@"SDAlertView dealloc");
}

@end

不定参数获取

在初始化方法initWithTitle中,我们需要获取不定参数,这里通过va_list指针,获取参数代码如下

// 后面的不定参数,可以使用va_list来获取
            //va_list 是一个指针变量  本质上是一个指针
            va_list arg_lists;
            //初始化 va_list
            va_start(arg_lists, otherButtonTitles);
            
            NSString * obj = nil;
            //va_arg(arg_lists, NSString*)用户来获取值
            while((obj=va_arg(arg_lists, NSString*))){
                if (obj && obj.length > 0) {
                    [tmpTitleList addObject:[NSString stringWithFormat:@"%@", obj]];
                }
            };
            //结束参数获取
            va_end(arg_lists);

静态sd_alertSheets和UIAlertAction扩展

sd_alertSheets是一个静态数组,使用sd_alertSheets是为了保证SDAlertView在代理事件处理后再释放SDAlertView对象,调用其dealloc方法。

// 采用这种方式,当点击的时候,将其从列表移除,防止在调用handleAlertAction时候self被释放掉了。
// 调用handleAlertAction,将其从数组中移除,移除后自动调用dealloc方法

UIAlertAction为增加属性,动态增加属性,一般采用runtime的方法。

#import <UIKit/UIKit.h>

static NSMutableArray *sd_alertSheets;

@interface UIAlertAction (SDIndex)

@property (nonatomic, assign) NSInteger actionIndex;

@end
#import "UIAlertAction+SDIndex.h"

static void *kActionIndexStrKey = &kActionIndexStrKey;

@implementation UIAlertAction (CSExt)

- (NSInteger)actionIndex {
    NSNumber *actionIndxNum = objc_getAssociatedObject(self, kActionIndexStrKey);
    return [actionIndxNum integerValue];
}

- (void)setActionIndex:(NSInteger)actionIndex {
    objc_setAssociatedObject(self, kActionIndexStrKey, [NSNumber numberWithInteger:actionIndex], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end

封装好SDAlertView类,替换工程UIAlertView

封装好SDAlertView类,替换工程UIAlertView,这时候,我们可以全局替换掉系统的UIAlertView,将UIAlertView替换成SDAlertView即可。

当然系统中的UIActionSheet替换方式一样,可以自定义类SDActionSheet采用同样的方式替换。

对于一些方法addButtonWithTitle、buttonTitleAtIndex、cancelButtonIndex您也可以尝试新增一些方法完善一下。

小结

iOS开发 在处理一些代码时候,自己常用的做法做一层封装,方便统一管理与替换。https://blog.csdn.net/gloryFlow/article/details/144538615

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/938589.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【大模型微调学习5】-大模型微调技术LoRA

【大模型微调学习5】-大模型微调技术LoRA LoRa微调1.现有 PEFT 方法的局限与挑战2.LoRA: 小模型有大智慧 (2021)3.AdaLoRA: 自适应权重矩阵的高效微调 (2023)4.QLoRA: 高效微调量化大模型 (2023) LoRa微调 1.现有 PEFT 方法的局限与挑战 Adapter方法&#xff0c;通过增加模型深…

Windows server服务器之网络安全管理(防火墙入站规则创建)

任务14.1 Windows server 防火墙的管理 系统防火墙概述&#xff1a;无论哪一种操作系统都有自己的防火墙&#xff0c;无论是客户端OS还是服务器端的NOS都有防火墙。 winr-control----打开控制面板 上图是Windows客户端的防火墙&#xff0c;三个重点要关注的内容&#xff1b;网…

【Python】PyWebIO 初体验:用 Python 写网页

目录 前言1 使用方法1.1 安装 Pywebio1.2 输出内容1.3 输入内容 2 示例程序2.1 BMI 计算器2.2 Markdown 编辑器2.3 聊天室2.4 五子棋 前言 前两天正在逛 Github&#xff0c;偶然看到一个很有意思的项目&#xff1a;PyWebIo。 这是一个 Python 第三方库&#xff0c;可以只用 P…

四、CSS3

一、CSS3简介 1、CSS3概述 CSS3 是 CSS2 的升级版本&#xff0c;他在CSS2的基础上&#xff0c;新增了很多强大的新功能&#xff0c;从而解决一些实际面临的问题。 CSS在未来会按照模块化的方式去发展&#xff1a;https://www.w3.org/Style/CSS/current-work.html …

Loki 微服务模式组件介绍

目录 一、简介 二、架构图 三、组件介绍 Distributor&#xff08;分发器&#xff09; Ingester&#xff08;存储器&#xff09; Querier&#xff08;查询器&#xff09; Query Frontend&#xff08;查询前端&#xff09; Index Gateway&#xff08;索引网关&#xff09…

上海亚商投顾:创业板指缩量下跌 多只高位股午后跌停

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 市场全天震荡调整&#xff0c;创业板指领跌&#xff0c;高位股开始出现退潮&#xff0c;建设工业、星光股份、…

libnanomsg详解

libnanomsg&#xff0c;或简称为nanomsg&#xff0c;是一个高性能的消息传递库&#xff0c;它为开发者提供了简单且高效的“可扩展协议”实现。以下是对libnanomsg的详细解析&#xff1a; 一、基本概述 项目地址&#xff1a;GitCode - 全球开发者的开源社区,开源代码托管平台 …

MySQL基础大全(看这一篇足够!!!)

文章目录 前言一、初识MySQL1.1 数据库基础1.2 数据库技术构成1.2.1 数据库系统1.2.2 SQL语言1.2.3 数据库访问接口 1.3 什么是MySQL 二、数据库的基本操作2.1 数据库创建和删除2.2 数据库存储引擎2.2.1 MySQL存储引擎简介2.2.2 InnoDB存储引擎2.2.3 MyISAM存储引擎2.2.4 存储引…

geoserver 瓦片地图,tomcat和nginx实现负载均衡

在地理信息系统&#xff08;GIS&#xff09;领域&#xff0c;GeoServer作为一个强大的开源服务器&#xff0c;能够发布各种地图服务&#xff0c;包括瓦片地图服务。为了提高服务的可用性和扩展性&#xff0c;结合Tomcat和Nginx实现负载均衡成为了一个有效的解决方案。本文将详细…

Spark执行计划解析后是如何触发执行的?

在前一篇Spark SQL 执行计划解析源码分析中&#xff0c;笔者分析了Spark SQL 执行计划的解析&#xff0c;很多文章甚至Spark相关的书籍在讲完执行计划解析之后就开始进入讲解Stage切分和调度Task执行&#xff0c;每个概念之间没有强烈的关联&#xff0c;因此这中间总感觉少了点…

前端的知识(部分)

11 前端的编写步骤 第一步:在HTML的页面中声明方法 第二步:在<script>中定义一个函数,其中声明一个data来为需要的数据 赋值一个初始值 第三步:编写这个方法实现对应的功能

网络编程中的黏包和半包问题

引言 - 什么是黏包和半包&#xff1f; 在网络编程中&#xff0c;黏包和半包问题是常见的数据传输问题&#xff0c;尤其是在使用TCP协议时。Netty作为一个高性能的网络框架&#xff0c;提供了多种解决方案来处理这些问题。下面我将详细解释黏包和半包问题&#xff0c;以及Netty…

F5中获取客户端ip地址(client ip)

当F5设备对其原始设置上的所有IP地址使用NAT时&#xff0c;连接到poo成员&#xff08;nodes、backend servers&#xff09;的出站连接将是NAT IP地址。 pool 成员&#xff08;nodes、backend servers&#xff09;将无法看到真实的客户端 ip地址&#xff0c;因为看到的是F5上的…

【容器】k8s学习笔记原理详解(十万字超详细)

Pod详解 Pod介绍 Pod结构 每个Pod中都可以包含一个或者多个容器&#xff0c;这些容器可以分为两类&#xff1a; 用户程序所在的容器&#xff0c;数量可多可少Pause容器&#xff0c;这是每个Pod都会有的一个根容器&#xff0c;它的作用有两个&#xff1a; 可以以它为依据&am…

【他山之石】Leading-Trim: The Future of Digital Typesetting:数字排版的未来 —— Leading-Trim

文章目录 【他山之石】Leading-Trim: The Future of Digital Typesetting&#xff1a;数字排版的未来 —— Leading-TrimHow an emerging CSS standard can fix old problems and raise the bar for web apps1. The problem with text boxes today2. How we got here: a histor…

vue3修改elementui-plus的默认样式的几种方法

#创作灵感 今天写vue的前端项目&#xff0c;因为需要去修改elementui-plus中drawer的默认样式&#xff0c;所以刚好将修改步骤记录下来。 一共提供了三种方法&#xff0c;但亲测第二种最好用。 使用第二种是可以无视自己的代码中是否定义了该盒子&#xff0c;因为有时候盒子的…

Qt WORD/PDF(四)使用 QAxObject 对 Word 替换(QWidget)

关于QT Widget 其它文章请点击这里: QT Widget 国际站点 GitHub: https://github.com/chenchuhan 国内站点 Gitee : https://gitee.com/chuck_chee 姊妹篇: Qt WORD/PDF&#xff08;一&#xff09;使用 QtPdfium库实现 PDF 操作 Qt WORD/PDF&#xff08;二…

MaskGCT——开源文本转语音模型,可模仿任何人说话声音

前期介绍过很多语音合成的模型&#xff0c;比如ChatTTS&#xff0c;微软语音合成大模型&#xff0c;字节跳动自家发布的语音合成模型Seed-TTS。其模型随着技术的不断发展&#xff0c;模型说话的声音也越来越像人类&#xff0c;虽然 seed-tts 可以进行语音合成等功能&#xff0c…

socket编程UDP-实现滑动窗口机制与累积确认GBN

在下面博客中&#xff0c;我介绍了利用UDP模拟TCP连接、按数据包发送文件的过程&#xff0c;并附上完整源码。 socket编程UDP-文件传输&模拟TCP建立连接脱离连接&#xff08;进阶篇&#xff09;_udp socket发送-CSDN博客 下面博客实现了停等机制。 socket编程UDP-实现停…

Linux 网络流量控制 - 实现概述

摘要 Linux 提供了一整套丰富的流量控制(traffic control)功能。本文档概述了相应的内核代码设计&#xff0c;描述了其结构&#xff0c;并通过描述一种新的排队策略来说明新元素的添加。 1 引言 最近的Linux内核提供了多种流量控制功能。Alexey Kuznetsov&#xff08;kuznet…