iOS项目技巧+封装过程

2023-10-29

前言

接手一个外包项目,发现问题颇多,下面是对整个项目封装过程的记录!

当前项目存在的问题

1: 接口前缀太多,切换环境不方便
2: 通用方法没有进行封装 -> 支付方法哪里用到写哪里
3: 扩展性和容错率太低!许多数组取值是直接根据数组下标来取的
4: 宏定义乱用 -> 用户数据没有进行封装,直接用宏来写

封装过程

1.对接口的处理

为什么不合理

之前的项目接口前缀是直接写在pch文件中,每次切换环境需要来回注释,十分的不方便。
而且pch文件本身是预编译环境,不做改动的代码才是这里的最佳选择,如果网络环境需要经常切换,存放在这里就不是很合理!

解决方案

网络环境一般为本地测试、预发布环境、正式环境。
我们可以使用三个pilst文件来对其进行封装。切换一次网络环境,只需要切换对应的plist文件即可。

好处

1.切换环境十分方便快捷,额其实这一条就够了,下面是方便切换网络环境的好处
2.在扩展方面十分方便,想想你的测试微信账号和正式账号的切换
3.方便后台和测试MM测试,想想你正在忙着撸代码呢?测试MM一会让你切换正式网络环境,一会让你切换本地环境。每次都需要重新打包,是不是很烦躁,不要怕,在APP的某一处,偷偷的用上一个点击方法,可以让她自由切换哦!
切换网络环境

图文介绍

1.创建plist文件
plist文件.png
.
2.根据场景调用对应的plist文件

- (void)setAppType:(XBApp_Type)type{
    NSString *path = nil;
    switch (type) {
        case XBApp_Type_Local:
            path =  [[NSBundle mainBundle] pathForResource:@"LocalNetworkProtocol" ofType:@"plist"];
            break;
        case XBApp_Type_Debug:
            path =  [[NSBundle mainBundle] pathForResource:@"DebugNetworkProtocol" ofType:@"plist"];
            break;
        case XBApp_Type_Release:
            path =  [[NSBundle mainBundle] pathForResource:@"ReleaseNetworkProtocol" ofType:@"plist"];
            break;
        default:  NSLog(@"-------- 警告!未选择打包模式 --------------");
            break;
    }
    _customMadeDic = [NSDictionary dictionaryWithContentsOfFile:path] ;
}

2.对通用方法的处理

对常用的方法做一些分类,比如判断字符串是否为空,判断字符串是否为电话号码,判断字符串是否为url等等….这些分类可以让你快速的开发。

3.尽量不要采取数组下标进行取值

在项目中,经常要截取一些url的参数,不要采用下标取值,正确姿势是写一个url的解析分类,获取url中对应的参数

警告:这是一个错误姿势

    NSString * string = @"https://112.112.112.112/apinew/customPage?groupId=6&sign=a7522acd73eeef8cd6f8c5c04c1b17f2&timeline=201702171414&appStartToken=&version=1.5.5";
    NSArray * ary = [string componentsSeparatedByString:@"&"];
if ([string rangeOfString:@"shop_checks"].location != NSNotFound) {
        NSString * specValue = [[ary[4] componentsSeparatedByString:@"="] lastObject];
        NSString * num = [[ary[3] componentsSeparatedByString:@"="] lastObject];
        NSString * skuProductId = [[ary[2] componentsSeparatedByString:@"="] lastObject];
        NSString * productId = [[ary[1] componentsSeparatedByString:@"="] lastObject];
}

正确的解锁姿势,写一个分类取出URL中的参数

// 将URL中得参数转化成字典
+ (NSDictionary*)getURLParameter:(NSString*)urlString{
    if (urlString.length == 0) {
        return  nil;
    }
    NSMutableDictionary *dict =[NSMutableDictionary dictionary];
    NSArray *urlArray = [urlString componentsSeparatedByString:@"?"];

    if (urlArray.count > 1) {   //如果大于1,认为有参数
        NSString *URLParString = [urlArray lastObject];

        if ([URLParString rangeOfString:@"&"].location != NSNotFound) { //多个参数
            NSArray *dictArray = [URLParString componentsSeparatedByString:@"&"];
            for (NSString *KVString in dictArray) {
                NSArray *KVArray = [KVString componentsSeparatedByString:@"="];
                for (int i = 0; i < KVArray.count; i++) {
                    if (i == KVArray.count - 1) {
                        [dict setValue:KVArray[i] forKey:KVArray[i - 1]];
                    }
                }
            }
        }else if ([URLParString rangeOfString:@"="].location != NSNotFound){ //单个参数
            NSArray *dictArray = [URLParString componentsSeparatedByString:@"="];
            for (int i = 0; i < dictArray.count; i++) {
                if (i == dictArray.count - 1) {
                    [dict setValue:dictArray[i] forKey:dictArray[i - 1]];
                }
            }
        }
    }

    return dict;
}

这只是其中一个例子,在项目中尽量不要采用数组下标取值这种操作。这种操作相对系统来说是危险的。
弊端有两方面:
1.容易造成系统崩溃
2.不容易对功能进行扩展

4.宏定义的使用

使用宏的话,尽量先对代码进行封装,再使用宏来简化代码。避免别人接手一脸懵逼的情况

警告:下面为错误示范

#define kUserId [[NSUserDefaults standardUserDefaults] objectForKey:@"userId"]
#define kuserName [[NSUserDefaults standardUserDefaults] objectForKey:@"userName"]
#define KuserLoginState [[NSUserDefaults standardUserDefaults] boolForKey:@"isLogined"]
#define kInitEntryId [[NSUserDefaults standardUserDefaults] objectForKey:@"initEntryId"]
#define kToken [[NSUserDefaults standardUserDefaults] objectForKey:@"kToken"]

这些是用户信息,完全可以使用一个模型先封装起来,后期想用宏处理的时候再用宏进行处理
正确的解锁姿势,先创建一个储存类,然后再创建一个用户类,加密可以选择SSKeychainss:

1.创建储存类

.h文件
#import <Foundation/Foundation.h>
#import "XBUserdefaultDefine.h"
#import <UIKit/UIKit.h>

@interface XBUserDefault : NSObject
+ (id)sharedWXUserDefault;

- (NSInteger)integerValueForKey:(NSString*)key;
- (BOOL)boolValueForKey:(NSString*)key;
- (NSString*)textValueForKey:(NSString*)key;
- (NSDictionary*)dicValueForKey:(NSString*)key;
- (CGFloat)floatValueForKey:(NSString*)key;
- (void)setInteger:(NSInteger)value forKey:(NSString*)key;
- (void)setBool:(BOOL)value forKey:(NSString*)key;
- (void)setFloat:(float)value forkey:(NSString*)key;
- (void)setObject:(id)object forKey:(NSString*)key;

- (void)removeObjectForKey:(NSString*)key;
- (NSArray*)allKeys;
- (BOOL)hasKey:(NSString*)key;
@end

.m文件
#import "XBUserDefault.h"

@implementation XBUserDefault
+ (id)sharedWXUserDefault{
    static dispatch_once_t predicate;
    static XBUserDefault *sharedUserDefault = nil;
    dispatch_once(&predicate, ^{
        sharedUserDefault = [[XBUserDefault alloc] init];
    });
    return sharedUserDefault;
}

- (NSInteger)integerValueForKey:(NSString*)key{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    return [userDefaults integerForKey:key];
}
- (BOOL)boolValueForKey:(NSString*)key{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    return [userDefaults boolForKey:key];
}
- (NSString*)textValueForKey:(NSString*)key{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    return [userDefaults stringForKey:key];
}
- (NSDictionary*)dicValueForKey:(NSString*)key{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    return [userDefaults dictionaryForKey:key];
}
- (CGFloat)floatValueForKey:(NSString*)key{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    return [userDefaults floatForKey:key];
}
- (void)setInteger:(NSInteger)value forKey:(NSString*)key{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setInteger:value forKey:key];
    [userDefaults synchronize];
}
- (void)setBool:(BOOL)value forKey:(NSString*)key{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setBool:value forKey:key];
    [userDefaults synchronize];
}
- (void)setFloat:(float)value forkey:(NSString*)key{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setFloat:value forKey:key];
    [userDefaults synchronize];
}
- (void)setObject:(id)object forKey:(NSString*)key{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setObject:object forKey:key];
    [userDefaults synchronize];
}
- (void)removeObjectForKey:(NSString*)key{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults removeObjectForKey:key];
    [userDefaults synchronize];
}
- (NSArray*)allKeys{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    return [[userDefaults dictionaryRepresentation] allKeys];
}
- (BOOL)hasKey:(NSString*)key{
    NSArray *allKeys = [self allKeys];
    NSInteger index = [allKeys indexOfObject:key];
    return index != NSNotFound;
}
@end

2.创建用户对象

.h文件
#import <Foundation/Foundation.h>
@interface XBUserOBJ : NSObject
+(XBUserOBJ*)sharedUserOBJ;
-(void)setUser:(NSString*)user;    //设置帐号
-(void)setPwd:(NSString*)pwd;      //设置密码
- (void)setUserID:(NSString*)userID;  //用户ID
- (NSString*)user;
- (NSString*)pwd;
- (NSString*)userID;
- (NSString*)token;
-(void)removeAllUserInfo;
@end

.m文件
#import "XBUserOBJ.h"
#import "XBUserDefault.h"
@implementation XBUserOBJ

+(XBUserOBJ*)sharedUserOBJ{
    static dispatch_once_t onceToken;
    static XBUserOBJ *sharedUserOBJ = nil;
    dispatch_once(&onceToken,^{
        sharedUserOBJ = [[XBUserOBJ alloc] init];
    });
    return sharedUserOBJ;
}
-(void)setUser:(NSString *)user{
    XBUserDefault *userDefault = [XBUserDefault sharedWXUserDefault];
    [userDefault setObject:user forKey:XB_Userdefault_User];
}
-(void)setPwd:(NSString *)pwd{
    XBUserDefault *userDefault = [XBUserDefault sharedWXUserDefault];
    [userDefault setObject:pwd forKey:XB_Userdefault_Pwd];
}
- (void)setUserID:(NSString *)userID{
    XBUserDefault *userDefault = [XBUserDefault sharedWXUserDefault];
    [userDefault setObject:userID forKey:XB_Userdefault_UserID];
}
//获取
-(NSString*)user{
    XBUserDefault *userDefault = [XBUserDefault sharedWXUserDefault];
    return [userDefault textValueForKey:XB_Userdefault_User];
}
-(NSString*)pwd{
    XBUserDefault *userDefault = [XBUserDefault sharedWXUserDefault];
    return [userDefault textValueForKey:XB_Userdefault_Pwd];
}
- (NSString*)userID{
    XBUserDefault *userDefault = [XBUserDefault sharedWXUserDefault];
    return [userDefault textValueForKey:XB_Userdefault_UserID];
}
- (void)removeAllUserInfo{
    XBUserDefault *userDefault = [XBUserDefault sharedWXUserDefault];
    [userDefault removeObjectForKey:XB_Userdefault_UserID];
    [userDefault removeObjectForKey:XB_Userdefault_UserToken];
    [userDefault removeObjectForKey:XB_Userdefault_NewUserID];
    [userDefault removeObjectForKey:XB_Userdefault_User];
    [userDefault removeObjectForKey:XB_Userdefault_Pwd];
}

公共文件
#ifndef RKXB_XBUserdefaultDefine_h
#define RKXB_XBUserdefaultDefine_h
#pragma mark  ----  用户信息存储
#define XB_Userdefault_UserID @"XB_Userdefault_UserID"
#define XB_Userdefault_UserToken @"kToken"
#define XB_Userdefault_NewUserID @"XB_Userdefault_NewUserID"
#define XB_Userdefault_NewUserToken @"XB_Userdefault_NewUserToken"
#define XB_Userdefault_User  @"XB_Userdefault_User"
#define XB_Userdefault_Pwd   @"XB_Userdefault_Pwd"
#define XB_UserDefault_Type  @"XB_UserDefault_Type"
#endif

github下载地址:https://github.com/chuheridangwu/ExampleProject

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

iOS项目技巧+封装过程 的相关文章

  • 教妹学Java(二十一):一文带你了解面向对象编程的所有概念

    你好呀 我是沉默王二 是 Web 全栈开发进阶之路 的作者 CSDN 的博客之星 教妹学 Java 是一套非常有趣的付费专栏 除了继续保持幽默风趣的行风风格 我还力求把每一个知识点讲得透彻明白 保证你可以从中受益 成为一名优秀的 Java
  • 经典场效应管如何快速关断技巧-KIA MOS管

    mos管的快速关断原理 R4是Q1的导通电阻没有Q1就没有安装的必要了 当低电位来时Q1为泻放扩流管 功率MOS管怎样关断 能否用PWM实现 怎样实现 功率mosfet的三个端口 G极 D极 S极 G极控制mosfet的开通 关断 给GS极
  • iOS项目技巧+封装过程

    前言 接手一个外包项目 发现问题颇多 下面是对整个项目封装过程的记录 当前项目存在的问题 1 接口前缀太多 切换环境不方便 2 通用方法没有进行封装 gt 支付方法哪里用到写哪里 3 扩展性和容错率太低 许多数组取值是直接根据数组下标来取的
  • Java 前后端分离业务封装 对后端返回值进行封装 PageVO封装

    遇到前后端业务需要不一致时对Controller返回结果进行封装 后端返回结果 前后端分离后 web 端要求结果 counts 2694 pagesize 14 pages 8 page 66 items id 9009384 title
  • Java实体类中封装其他实体类并引用

    在Java开发过程中有很多情况是二个表及以上的联合操作 这是需要分清楚表的主次关系 在引用的时候有人会把二个表的数据全都封装在一个实体类中 然后在对这个实体类进行操作 但如果是三个表呢 四个表呢 还都封装在一个实体类吗 这样被封装的实体类的
  • 震惊,微信小程序可以设置网络字体!真香

    准备工作 获取字体链接 还原设计稿的时候需要用到如下特殊字体 google 的 Montserrat https fonts google com specimen Montserrat 选择这个字体 下载全部字体 将本地的字体文件上传到自
  • c++关于类成员函数中 参数列表中参数访问自身的私有变量

    本人的第四篇CSDN文章 有错误一定要指出啊啊啊啊啊啊啊啊啊啊 C 关于类的成员函数中 参数列表中访问参数的自身的私有变量 在做作业时候 在写类函数的时候遇到了问题 当参数列表为本类的参数时候 可以直接访问参数的私有变量 于是自己探究了下用
  • python语法--面向对象基础(19)

    1 初识面向对象 1 1 面向过程 面向过程 根据业务逻辑从上到下写代码 开发过程的思路是将数据与函数按照执行的逻辑顺序组织在一起 数据与函数分开考虑 面向过程基本是由函数组成的 特点 注重步骤与过程 不注重职责分工 如果需求复杂 代码会变
  • Easyx-----c++实现经典Windows扫雷

    一些说明 关于扫雷的基本实现 我在这篇博客已经详细介绍Easyx c语言实现简易版扫雷 考拉爱睡觉鸭 的博客 CSDN博客 这里不再描述 主要是以c 单例设计模式的方式实现扫雷 多加了右键点击笑脸作弊功能 不会扫雷的小伙伴也可以愉快玩耍了
  • R语言与面向对象的编程(3):R6类

    专注系列化 高质量的R语言教程 本号已支持快捷转载 无需白名单即可转载 本系列将介绍R语言中三个与面向对象的编程 Object Oriented Programming OOP 相关的工具包 proto R6和基础包methods 这是一个
  • Linux 系统安全如何设定 log 日志记录服务器

    在网上越来越多的黑客的出现 越来越多的高手出现的情况下 如何才能确保自己可以保存一份完整的 log 呢 稍微有点概念的黑客都知道 进入系统后的第一见事情就是去清理 log 而发现入侵的最简单最直接的方法就是去看系统纪录文件 现在我们来说说如
  • Vue + axios + vant 封装公共请求

    import axios from axios 引入axios import router from router 引入路由 import Toast from vant 引入提示层 export function post obj 调用时
  • Ajax定时调用封装

    var dataUpload ajax请求数据 method function murl mdata method time1 time2 success 首次读取 setTimeout function aJax time1 定时读取函数
  • Python最强知识点整理:面向对象封装案例

    面向对象封装案例 目标 封装 小明爱跑步 存放家具 01 封装 封装 是面向对象编程的一大特点 面向对象编程的 第一步 将 属性 和 方法 封装 到一个抽象的 类 中 外界 使用 类 创建 对象 然后 让对象调用方法 对象方法的细节 都被
  • CH07_封装

    封装记录 Encapsulate Record 162 曾用名 以数据类代替记录 Replace Record with Data Class organization name Acme Gooseberries country GB c
  • 2021-02-28

    simulink控制器封装库 控制器封装库 一 封装库的安装和LADRC模块的使用
  • AndroidStudio将module变为library

    文章注明出处可随意转载 请尊重别人的劳动成果 前言 在一个application当中 可能会存在多个module 有时也会有一个module包含其他module的需求 在完成这个需求时 Google了很多 全是2014年之前的一些老文章 现
  • [vue3]用element封装一个抽屉组件

    需求 因为抽屉组件在后台管理系统是非常常见的 那么封装起来怎么样 可以传入标题 size 提交按钮的文字 传入部分即便超出范围也不会挤掉下面的按钮 会出现滚动条 如图
  • python自动化笔记(十一)——openpyxl之封装

    封装一个可以读取任意excel文件的方法 可以指定读取的表单 当我们多次从excel中读取数据时 就不用重复地写代码 只需调用封装的类即可 一 封装的excel类实现的需求是什么 1 读取表头数据 2 读取表头以外的所有数据 返回值 列表
  • 3.[mybatis]的查询源码分析(执行流程、缓存、整合spring要点)

    目录 1 装饰器模式 2 sqlSession的创建 open 2 1 newExecutor 3 selectOne分析 3 1 二级缓存 3 2 一级缓存 4 数据库查询核心分析 queryFromDatabase 4 1 Simple

随机推荐

  • gcov代码覆盖率使用gcov完成代码覆盖率的测试

    Gcov作为gnu gcc工作组件之一 是一款的免费的代码覆盖率测试工具 而且可以结合lcov生成美观的html的测试报表 本文介绍一些gcov的使用方法 基本原理 一些实际中可能会遇到的问题以及解决思路 Gcov的用法 1 1 编译 Gc
  • 深度思考:老生常谈的双亲委派机制,JDBC、Tomcat是怎么反其道而行之的?

    要说双亲委派机制 还得从类加载器的类型谈起 一 类加载器的类型 类加载器有以下种类 启动类加载器 Bootstrap ClassLoader 扩展类加载器 Extension ClassLoader 应用类加载器 Application C
  • 【杭电错题】#12青年歌手大奖赛_评委会打分——最优解

    题目 青年歌手大奖赛中 评委会给参赛选手打分 选手得分规则为去掉一个最高分和一个最低分 然后计算平均得分 请编程输出某选手的得分 Input 输入数据有多组 每组占一行 每行的第一个数是n 2
  • 编程小技巧:四舍五入

    今天跟大家分享的小技巧是跟浮点数取整相关 我们知道计算机在为浮点数取整是通常是向零取整 也就是说会自动将浮点数的小数部分忽略掉 例如下面的例子 float a 3 68 int b int a 我们将变量a取整后赋值给变量b 则变量b的值为
  • 善用用户自定义信号

    kill l可以看到用户自定义信号 然后就可以在程序中注册使用此信号 通过killall 10 xxx 就可以给程序发送用户自定义信号 kill 6 可以让程序产生段错误
  • 2024王道408数据结构 P144 T10

    2024王道408数据结构 P144 T10 思考过程 这题也比较简单 首先看题目 要求我们用先序遍历求二叉树中第k个结点的值 那道理我们都懂直接开始敲代码 先建立一个计数器i和一个char类型的值ch 用来暂时存放data值 当i k时就
  • Golang vs Rust 为后端选择哪种语言?

    如果您的项目涉及 Web 开发 可分发服务器 那么建议您选择 Go 编程部分非常简单 并发模型将为您提供很多帮助 但是如果你打算开发一个 CLI 应用程序 那么你应该选择 Rust 因为它包含字符串处理和库 话虽如此 Rust 并不是最容易
  • idea-eclipse风格-快捷键大全总结

    文章目录 IDEA 快捷键风格选型 idea 快捷键总结 idea常用快捷键 与eclipse风格冲突的快捷键 代码自动提示快捷键 快速创建方法的快捷键 与eclipse使用不同 复制类的完整路径名 包名 类名 idea自身的快捷键被ecl
  • 《C#入门经典(第6版)》之如何编写简单的桌面应用程序

    1本章内容 Visual Studio 2012 的基础知识 如何编写简单的控制台应用程序 如何编写简单的桌面应用程序 VS 是一个庞大的复杂产品 可能会使初学者望而生畏 但使 用它创建简单的应用程序是非常容易的 在本章开始使用VS 时 不
  • 【从零开始学习Linux】常用命令及操作

    哈喽 哈喽 大家好 我是你们的老朋友 保护小周 本期给大家带来的是 Linux 常用命令及操作 主要有三个分类 文件操作 目录操作 网络操作 创建文件 touch 创建目录 mkdir 删除文件或目录 rm 文本编辑器 vim 查看文件内容
  • 《企业管理学》——决策与决策方法知识点总结

    第四讲 决策与决策方法 管理的核心是决策 正确的决策决胜千里 错误的决策南辕北辙 一 决策的重要性 概念及内涵 一 决策的重要性 决策是管理者从事管理工作的基础 在管理过程中 管理者会面临各种各样的问题 它们都需要管理者予以解决 在实际管理
  • Linux安装tomcat

    一 下载tomcat 打开tomcat下载页面 tomcat10下载页面 如果你 不想做代码的迁移工作 可以选择Tomcat9及其以下的版本 我们这里是为了安装Tomcat 选择Tomcat9作为演示的版本 二 解压 将下载好的Tomcat
  • HowTo如何制作一个文字冒险游戏-里篇(1)

    从一个文字冒险引擎开始 引 文字冒险游戏 顾名思义是以文字为主体的冒险游戏 其体现形式包含交互式小说 养成游戏 恋爱冒险等等 通过文字和音画表现情境戏以软件模拟情境 令玩家使用文字指令控制角色 以影响周边的情境 其运作方式可以理解成是用电脑
  • 软件测试必备知识框架图

    转载于 https www cnblogs com yinlili p 10075399 html
  • 【数据结构和算法】超多图解,超详细,堆详解

    作者 Linux猿 简介 CSDN博客专家 华为云享专家 数据结构和算法 C C 面试 刷题 Linux尽管咨询我 关注我 有问题私聊 关注专栏 图解数据结构和算法 优质好文持续更新中 欢迎小伙伴们点赞 收藏 留言 目录 一 什么是堆
  • mkdocs 部署教程

    一 安装mkdocs pip install mkdocs 二 创建项目 mkdocs new testdocs 三 文档预览 mkdocs serve 四 更换主题 下载主题 pip install mkdocs material mkd
  • IDEA,debug时出现FileNotFoundException: C:\Users\Àîê»\AppData\Local\Temp\capture83.prop (系统找不到指定的路径)的问题

    解决办法 修改你的电脑用户名 用IDEA时 运行没问题 debug就报错 原因是 你电脑C盘用户下的用户名有中文 或者其他的字符 导致找文件的时候翻译成乱码 所以出错 1 需要创建新的本地用户 点击桌面左下角win图标找到windows系统
  • 通过端口号查找进程、程序名和命令行信息

    通过端口号查找进程 程序名和命令行信息 在Linux系统中 我们经常需要根据端口号查找正在运行的进程及其相关信息 本文将介绍如何使用编程的方式通过端口号查找进程 程序名和命令行信息 在Linux中 可以使用netstat命令或ss命令来查看
  • Winform各控件详解(笔记)

    DataGridView简称DGV http www cnblogs com 08shiyan archive 2010 08 10 1796768 html
  • iOS项目技巧+封装过程

    前言 接手一个外包项目 发现问题颇多 下面是对整个项目封装过程的记录 当前项目存在的问题 1 接口前缀太多 切换环境不方便 2 通用方法没有进行封装 gt 支付方法哪里用到写哪里 3 扩展性和容错率太低 许多数组取值是直接根据数组下标来取的