最近项目上需要用到一个选择器,选择器中的内容只有年和月,而在iOS系统自带的日期选择器UIDatePicker中却只有四个选项如下,分别是时间(时分秒)、日期(年月日)、日期+时间(年月日时分)以及倒计时。其中并没有我们所需要的只显示年月的选择器,在网上找了很多相关的资料,但是觉得都写得过于麻烦。因此,为了满足项目需求,自己用UIPickerView写了一个只显示年月的选择器界面,同时还可以控制我们的显示的最小时间。当然,如果要控制其他内容也都是可以的,无非就是在数据处理上多一些处理和控制。

typedef NS_ENUM(NSInteger, UIDatePickerMode) {
UIDatePickerModeTime, // Displays hour, minute, and optionally AM/PM designation depending on the locale setting (e.g. 6 | 53 | PM)
UIDatePickerModeDate, // Displays month, day, and year depending on the locale setting (e.g. November | 15 | 2007)
UIDatePickerModeDateAndTime, // Displays date, hour, minute, and optionally AM/PM designation depending on the locale setting (e.g. Wed Nov 15 | 6 | 53 | PM)
UIDatePickerModeCountDownTimer, // Displays hour and minute (e.g. 1 | 53)
} __TVOS_PROHIBITED;

一 整体方案 

  在整个实现中分为两个部分,首先是用一个基类来布局我们选择器的整体布局,包括我们的选择器的标题,取消、确定按钮,蒙层等大框架的布局,然后是子类在基类的基础上添加UIPickerView来实现选择器的基本功能以及数据加载和显示。首先,我们来看一下整体的一个效果,点击某个设定的控件,然后弹出下图所示的一个选择器,选择器的选项主要就是显年月的信息:

二 基类布局

  在上一部分说了,基类布局主要是对整体的架构进行布局,我们先看下有哪些内容,包括了背景蒙层视图、弹出视图(包含标题行(又包含取消按钮、确定按钮和标题)、分割线和选择器),在子类中会进行一个整体的布局,在 - (void)initUI 方法中进行布局。

//
// BaseView.h #import <UIKit/UIKit.h> #define kDatePicHeight 200 //选择器的高度
#define kTopViewHeight 44 //取消 标题 确定 行高度 #define SCREEN_BOUNDS [UIScreen mainScreen].bounds
#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
#define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
@interface BaseView : UIView
// 背景蒙层视图
@property (nonatomic, strong) UIView *backgroundView;
// 弹出视图
@property (nonatomic, strong) UIView *alertView;
// 标题行顶部视图
@property (nonatomic, strong) UIView *topView;
// 左边取消按钮
@property (nonatomic, strong) UIButton *leftBtn;
// 右边确定按钮
@property (nonatomic, strong) UIButton *rightBtn;
// 中间标题
@property (nonatomic, strong) UILabel *titleLabel;
// 分割线视图
@property (nonatomic, strong) UIView *lineView; /** 初始化子视图 ,整体布局*/
- (void)initUI; //以下三种方法在基类中的实现都是空白的,具体的效果在子类中重写
/** 点击背景遮罩图层事件 */
- (void)didTapBackgroundView:(UITapGestureRecognizer *)sender;
/** 取消按钮的点击事件 */
- (void)clickLeftBtn;
/** 确定按钮的点击事件 */
- (void)clickRightBtn; @end

  具体的.m文件的实现代码如下,进行折叠了,需要的可以直接拷贝,在后面我们再 进行具体分析每一步的布局和设置。

 //
// BaseView.m
// CJMobile
//
// Created by mukekeheart on 2017/12/12.
// Copyright © 2017年 长江证券. All rights reserved.
// #import "BaseView.h" @implementation BaseView - (void)initUI {
self.frame = SCREEN_BOUNDS;
// 背景遮罩图层
[self addSubview:self.backgroundView];
// 弹出视图
[self addSubview:self.alertView];
// 设置弹出视图子视图
// 添加顶部标题栏
[self.alertView addSubview:self.topView];
// 添加左边取消按钮
[self.topView addSubview:self.leftBtn];
// 添加右边确定按钮
[self.topView addSubview:self.rightBtn];
// 添加中间标题按钮
[self.topView addSubview:self.titleLabel];
// 添加分割线
[self.topView addSubview:self.lineView];
} #pragma mark - 背景遮罩图层
- (UIView *)backgroundView {
if (!_backgroundView) {
_backgroundView = [[UIView alloc]initWithFrame:SCREEN_BOUNDS];
_backgroundView.backgroundColor = [UIColor blackColor] ;
_backgroundView.alpha = 0.3f ;
_backgroundView.userInteractionEnabled = YES;
UITapGestureRecognizer *myTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(didTapBackgroundView:)];
[_backgroundView addGestureRecognizer:myTap];
}
return _backgroundView;
} #pragma mark - 弹出视图
- (UIView *)alertView {
if (!_alertView) {
_alertView = [[UIView alloc]initWithFrame:CGRectMake(, SCREEN_HEIGHT - kTopViewHeight - kDatePicHeight, SCREEN_WIDTH, kTopViewHeight + kDatePicHeight)];
_alertView.backgroundColor = [UIColor whiteColor];
}
return _alertView;
} #pragma mark - 顶部标题栏视图
- (UIView *)topView {
if (!_topView) {
_topView =[[UIView alloc]initWithFrame:CGRectMake(, , SCREEN_WIDTH, kTopViewHeight + 0.5)];
_topView.backgroundColor = [UIColor whiteColor];
}
return _topView;
} #pragma mark - 左边取消按钮
- (UIButton *)leftBtn {
if (!_leftBtn) {
_leftBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_leftBtn.frame = CGRectMake(, , , );
_leftBtn.backgroundColor = [UIColor clearColor];
_leftBtn.layer.masksToBounds = YES;
_leftBtn.titleLabel.font = [UIFont systemFontOfSize:17.0f];
[_leftBtn setTitleColor:kGrayFontColor forState:UIControlStateNormal];
[_leftBtn setTitle:@"取消" forState:UIControlStateNormal];
[_leftBtn addTarget:self action:@selector(clickLeftBtn) forControlEvents:UIControlEventTouchUpInside];
}
return _leftBtn;
} #pragma mark - 右边确定按钮
- (UIButton *)rightBtn {
if (!_rightBtn) {
_rightBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_rightBtn.frame = CGRectMake(SCREEN_WIDTH - , , , );
_rightBtn.backgroundColor = [UIColor clearColor];
_rightBtn.layer.masksToBounds = YES;
_rightBtn.titleLabel.font = [UIFont systemFontOfSize:17.0f];
[_rightBtn setTitleColor:kBlueFontColor forState:UIControlStateNormal];
[_rightBtn setTitle:@"确定" forState:UIControlStateNormal];
[_rightBtn addTarget:self action:@selector(clickRightBtn) forControlEvents:UIControlEventTouchUpInside];
}
return _rightBtn;
} #pragma mark - 中间标题按钮
- (UILabel *)titleLabel {
if (!_titleLabel) {
_titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(, , SCREEN_WIDTH - , kTopViewHeight)];
_titleLabel.backgroundColor = [UIColor clearColor];
_titleLabel.font = [UIFont systemFontOfSize:17.0f];
_titleLabel.textColor = kBlackFontColor;
_titleLabel.textAlignment = NSTextAlignmentCenter;
}
return _titleLabel;
} #pragma mark - 分割线
- (UIView *)lineView {
if (!_lineView) {
_lineView = [[UIView alloc]initWithFrame:CGRectMake(, kTopViewHeight, SCREEN_WIDTH, 0.5)];
_lineView.backgroundColor = [UIColor colorWithRed: / 255.0 green: / 255.0 blue: / 255.0 alpha:1.0];
[self.alertView addSubview:_lineView];
}
return _lineView;
} #pragma mark - 点击背景遮罩图层事件
- (void)didTapBackgroundView:(UITapGestureRecognizer *)sender { } #pragma mark - 取消按钮的点击事件
- (void)clickLeftBtn { } #pragma mark - 确定按钮的点击事件
- (void)clickRightBtn { } @end

BaseView.m

  在BaseView.m中主要是对整体框架进行布局,我们的控件的位置都是通过绝对位置进行布局的,所以需要修改的在话可以直接在对应的位置上进行修改,然后在BaseView.h中的注释我们说过了,点击背景遮罩图层和取消、确定按钮的点击事件实现效果在基类中都是空白的,具体效果在子类中进行重写来控制。而对于弹出视图中的标题行(包含取消按钮、确定按钮和标题)、分割线和选择器的具体布局在这里就不进行展开了,很简单的部分,大家自行看一下代码就OK了。

  下面主要提两个问题:一个是整体布局的方法 - (void)initUI 的实现。这里大家主要要注意的添加的层次,谁是谁的子视图,一定要区分清楚。

- (void)initUI {
self.frame = SCREEN_BOUNDS;
// 背景遮罩图层
[self addSubview:self.backgroundView];
// 弹出视图
[self addSubview:self.alertView];
// 设置弹出视图子视图
// 添加顶部标题栏
[self.alertView addSubview:self.topView];
// 添加左边取消按钮
[self.topView addSubview:self.leftBtn];
// 添加右边确定按钮
[self.topView addSubview:self.rightBtn];
// 添加中间标题按钮
[self.topView addSubview:self.titleLabel];
// 添加分割线
[self.topView addSubview:self.lineView];
}

  二是我们的背景蒙层和弹出视图大家可以通过代码看到蒙层遮罩背景的布局是整个屏幕,那么我们为什么不直接在蒙层上添加弹出式图呢?如果直接在蒙层上添加弹出式图作为子视图的话,我们的布局相对会简单很多,这里涉及到一点就是子视图的透明度是和父视图保持一致的,如果直接将弹出视图加载到蒙层遮罩视图上,会导致弹出视图的透明度也为0.3,所以弹出视图不能直接加在蒙层遮罩视图上,而是需要加在当前界面上。

- (UIView *)backgroundView {
if (!_backgroundView) {
_backgroundView = [[UIView alloc]initWithFrame:SCREEN_BOUNDS];
_backgroundView.backgroundColor = [UIColor blackColor] ;
_backgroundView.alpha = 0.3f ;
_backgroundView.userInteractionEnabled = YES;
UITapGestureRecognizer *myTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(didTapBackgroundView:)];
[_backgroundView addGestureRecognizer:myTap];
}
return _backgroundView;
} // 背景遮罩图层
[self addSubview:self.backgroundView];
// 弹出视图
[self addSubview:self.alertView];

三 子类选择器实现

  首先是我们的子类向外暴露的方法只有一个类方法,该方法主要是让使用者提供选择器的标题、最小日期、日期选择完成后的操作等基本信息,方便我们对选择器的数据和操作进行设置。对外暴露类方法也是避免使用者在使用时需要创建对象,比较麻烦,也避免一些不必要的问题。

//
// CJYearMonthSelectedView.h #import <UIKit/UIKit.h>
#import "BaseView.h" //日期选择完成之后的操作
typedef void(^BRDateResultBlock)(NSString *selectValue); @interface CJYearMonthSelectedView : BaseView //对外开放的类方法
+ (void)showDatePickerWithTitle:(NSString *)title minDateStr:(NSString *)minDateStr resultBlock:(BRDateResultBlock)resultBlock; @end

  关于具体的子类的实现,还是先把所有代码都贴上来,有点多,所以折叠一下,后面对其中一些要点进行列出说明一下。还有取消、确定按钮的点击事件也都在这里进行控制和实现,我们根据自己的需要进行这是就可以了,一般是在点击确定按钮的时候调用我们的BRDateResultBlock,实现日期选择完成的操作。其中取消按钮就直接没有操作,dismiss当前界面,并注意要进行dealloc,创建的视图要清除,避免内存泄露。蒙层背景点击事件看需求,有的需要和取消一样的效果,有的可能就无效果,自己添加即可。

 //  CJYearMonthSelectedView.m

 #import "CJYearMonthSelectedView.h"

 @interface CJYearMonthSelectedView () <UIPickerViewDelegate,UIPickerViewDataSource>
@property (strong, nonatomic) UIPickerView *picker; //选择器
@property (copy, nonatomic) NSString *title;
@property (copy, nonatomic) NSString *minDateStr;
@property (assign, nonatomic) BRDateResultBlock resultBlock;
@property (copy, nonatomic) NSString *selectValue; //选择的值
@property (strong, nonatomic) NSMutableArray<NSString *> *data; @end @implementation CJYearMonthSelectedView + (void)showDatePickerWithTitle:(NSString *)title minDateStr:(NSString *)minDateStr resultBlock:(BRDateResultBlock)resultBlock{ CJYearMonthSelectedView *datePicker = [[CJYearMonthSelectedView alloc] initWithTitle:title minDateStr:minDateStr resultBlock:resultBlock];
[datePicker showWithAnimation:YES];
} //初始化方法
- (instancetype)initWithTitle:(NSString *)title minDateStr:(NSString *)minDateStr resultBlock:(BRDateResultBlock)resultBlock{
if (self = [super init]) {
_title = title;
_minDateStr = minDateStr;
_resultBlock = resultBlock; [self initUI];
} return self;
} //UI布局,主要就是在弹出视图上添加选择器
- (void)initUI{
[super initUI];
self.titleLabel.text = _title;
// 添加时间选择器
[self.alertView addSubview:self.picker];
} //选择器的初始化和布局
- (UIPickerView *)picker{
if (!_picker) {
_picker = [[UIPickerView alloc] initWithFrame:CGRectMake(, kTopViewHeight + 0.5, SCREEN_WIDTH, kDatePicHeight)];
// _picker.backgroundColor = [UIColor whiteColor];
_picker.showsSelectionIndicator = YES;
//设置代理
_picker.delegate =self;
_picker.dataSource =self;
}
return _picker;
} //选择器数据的加载,从设定的最小日期到当前月
- (NSMutableArray<NSString *> *)data{
if (!_data) {
_data = [[NSMutableArray alloc] init];
NSDate *currentDate = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM"];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *lastMonthComps = [[NSDateComponents alloc] init];
NSString *dateStr = [formatter stringFromDate:currentDate];
NSInteger lastIndex = ;
NSDate *newdate;
//循环获取可选月份,从当前月份到最小月份
while (!([dateStr compare:self.minDateStr] == NSOrderedAscending)) {
[_data addObject:dateStr];
lastIndex--;
//获取之前几个月
[lastMonthComps setMonth:lastIndex];
newdate = [calendar dateByAddingComponents:lastMonthComps toDate:currentDate options:];
dateStr = [formatter stringFromDate:newdate];
}
}
return _data;
} #pragma mark - UIPickerView的数据和布局,和tableview类似
//返回多少列
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return ;
} //返回多少行
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
return self.data.count;
} //每一行的数据
-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
return self.data[row];
} //选中时的效果
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
self.selectValue = self.data[row];
} //返回高度
-(CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component{
return 35.0f;
} //返回宽度
-(CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component{
return ZYAppWidth;
} #pragma mark - 背景视图的点击事件
- (void)didTapBackgroundView:(UITapGestureRecognizer *)sender {
// [self dismissWithAnimation:NO];
} #pragma mark - 弹出视图方法
- (void)showWithAnimation:(BOOL)animation {
//1. 获取当前应用的主窗口
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
[keyWindow addSubview:self];
if (animation) {
// 动画前初始位置
CGRect rect = self.alertView.frame;
rect.origin.y = SCREEN_HEIGHT;
self.alertView.frame = rect;
// 浮现动画
[UIView animateWithDuration:0.3 animations:^{
CGRect rect = self.alertView.frame;
rect.origin.y -= kDatePicHeight + kTopViewHeight;
self.alertView.frame = rect;
}];
}
} #pragma mark - 关闭视图方法
- (void)dismissWithAnimation:(BOOL)animation {
// 关闭动画
[UIView animateWithDuration:0.2 animations:^{
CGRect rect = self.alertView.frame;
rect.origin.y += kDatePicHeight + kTopViewHeight;
self.alertView.frame = rect; self.backgroundView.alpha = ;
} completion:^(BOOL finished) {
[self.leftBtn removeFromSuperview];
[self.rightBtn removeFromSuperview];
[self.titleLabel removeFromSuperview];
[self.lineView removeFromSuperview];
[self.topView removeFromSuperview];
[self.picker removeFromSuperview];
[self.alertView removeFromSuperview];
[self.backgroundView removeFromSuperview];
[self removeFromSuperview]; self.leftBtn = nil;
self.rightBtn = nil;
self.titleLabel = nil;
self.lineView = nil;
self.topView = nil;
self.picker = nil;
self.alertView = nil;
self.backgroundView = nil;
}];
} #pragma mark - 取消按钮的点击事件
- (void)clickLeftBtn {
[self dismissWithAnimation:YES];
} #pragma mark - 确定按钮的点击事件
- (void)clickRightBtn {
NSLog(@"点击确定按钮后,执行block回调");
[self dismissWithAnimation:YES];
if (_resultBlock) {
_resultBlock(_selectValue);
}
} @end

CJYearMonthSelectedView.m

  这里面跟着流程看其实很简单哈,主要需要说明的一点就是UIPickerView的用法,UIPickerView其实和UITableView很类似,在初始化的时候需要设置其数据代理和视图代理(UIPickerViewDelegate,UIPickerViewDataSource),然后通过这两个代理进内容、行数、列数的控制。

- (UIPickerView *)picker{
if (!_picker) {
_picker = [[UIPickerView alloc] initWithFrame:CGRectMake(, kTopViewHeight + 0.5, SCREEN_WIDTH, kDatePicHeight)];
_picker.showsSelectionIndicator = YES;
//设置UIPickerView的代理
_picker.delegate =self;
_picker.dataSource =self;
}
return _picker;
}
#pragma mark - UIPickerView
//返回多少列
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return ;
} //返回多少行
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
return self.data.count;
} //每一行的数据
-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
return self.data[row];
} //选中时的效果
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
self.selectValue = self.data[row];
} //返回高度
-(CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component{
return 35.0f;
} //返回宽度
-(CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component{
return ZYAppWidth;
}

  关于数据的控制可以根据我们的需要进行设定,行数和列数也是根据我们的需求来进行控制。下面主要就是说一下如何获取年月这样的数据,主要是用到了NSDateComponents 的直接获取一个月前的信息,然后通过将NSCalendar将NSDateComponents转化为日期Date,最后将Date转化为我们需要的格式的数据。

//数据获取
- (NSMutableArray<NSString *> *)data{
if (!_data) {
_data = [[NSMutableArray alloc] init];
//当前日期时间
NSDate *currentDate = [NSDate date];
//设定数据格式为xxxx-mm
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM"];
//通过日历可以直接获取前几个月的日期,所以这里直接用该类的方法进行循环获取数据
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *lastMonthComps = [[NSDateComponents alloc] init];
NSString *dateStr = [formatter stringFromDate:currentDate];
NSInteger lastIndex = ;
NSDate *newdate;
//循环获取可选月份,从当前月份到最小月份,直接用字符串的比较来判断是否大于设定的最小日期
while (!([dateStr compare:self.minDateStr] == NSOrderedAscending)) {
[_data addObject:dateStr];
lastIndex--;
//获取之前n个月, setMonth的参数为正则向后,为负则表示之前
[lastMonthComps setMonth:lastIndex];
newdate = [calendar dateByAddingComponents:lastMonthComps toDate:currentDate options:];
dateStr = [formatter stringFromDate:newdate];
}
}
return _data;
}

四 使用方法

  关于自己做的这个在使用上就非常简单了,我们的子类向外就暴露了一个类方法,所以我们再需要弹出选择器的地方调用该方法就可以了。

- (void) btnPress:(UIButton *)sender{
if (sender.tag == ) { //导出 按钮
[CJYearMonthSelectedView showDatePickerWithTitle:@"选择月份" minDateStr:@"2017-10" resultBlock:^(NSString *selectValue) {
//选择完成后的操作
NSLog(@"selected month is %@", selectValue);
}];
} else { }
}

  以上就是使用UIPickerView自定义一个年月的选择器,包括最初的的完整的界面代码和具体的选择器的创建和布局,以及我们的数据处理。

iOS学习——UIPickerView的实现年月选择器的更多相关文章

  1. iOS学习之自定义弹出UIPickerView或UIDatePicker(动画效果)

    前面iOS学习之UIPickerView控件的简单使用 用到的UIPickerView弹出来是通过 textField.inputView = selectPicker;   textField.in ...

  2. iOS学习之UIPickerView控件的关联选择

    接上篇iOS学习之UIPickerView控件的简单使用 接着上篇的代码 http://download.csdn.net/detail/totogo2010/4391870 ,我们要实现的效果如下: ...

  3. ios 学习路线总结

    学习方法 面对有难度的功能,不要忙着拒绝,而是挑战一下,学习更多知识. 尽量独立解决问题,而不是在遇到问题的第一想法是找人. 多学习别人开源的第三方库,能够开源的库一定有值得学习的地方,多去看别的大神 ...

  4. iOS学习笔记-精华整理

    iOS学习笔记总结整理 一.内存管理情况 1- autorelease,当用户的代码在持续运行时,自动释放池是不会被销毁的,这段时间内用户可以安全地使用自动释放的对象.当用户的代码运行告一段 落,开始 ...

  5. iOS学习笔记总结整理

    来源:http://mobile.51cto.com/iphone-386851_all.htm 学习IOS开发这对于一个初学者来说,是一件非常挠头的事情.其实学习IOS开发无外乎平时的积累与总结.下 ...

  6. 2015最新iOS学习线路图

    iOS是由苹果公司开发的移动操作系统,以xcode为主要开发工具,具有简单易用的界面.令人惊叹的功能,以及超强的稳定性,已经成为iPhone.iPad 和iPod touch 的强大基础:iOS 内置 ...

  7. IOS学习笔记48--一些常见的IOS知识点+面试题

      IOS学习笔记48--一些常见的IOS知识点+面试题   1.堆和栈什么区别? 答:管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制:对于堆来说,释放工作由程序员控制,容易产生memor ...

  8. iOS学习笔记31-从图册获取图片和视频

    一.从图册中获取本地图片和视频 从图册中获取文件,我们使用的是UIImagePickerController,这个类我们在之前的摄像头中使用过,这里是链接:iOS学习笔记27-摄像头,这里我们使用的是 ...

  9. iOS学习-压缩图片(改变图片的宽高)

    压缩图片,图片的大小与我们期望的宽高不一致时,我们可以将其处理为我们想要的宽高. 传入想要修改的图片,以及新的尺寸 -(UIImage*)imageWithImage:(UIImage*)image ...

随机推荐

  1. Dockerfile 中的 CMD 与 ENTRYPOINT

    CMD 和 ENTRYPOINT 指令都是用来指定容器启动时运行的命令.单从功能上来看,这两个命令几乎是重复的.单独使用其中的一个就可以实现绝大多数的用例.但是既然 doker 同时提供了它们,为了在 ...

  2. 速卖通AE平台+聚石塔+奇门 完整教程V2

    公司是跨境电商,在阿里马马的速卖通平台上开有店铺,并且基于速卖通开放平台,自主研发了ERP系统,居今已有3年多的时间了,一直很稳定. 今年初,速卖通AE开放平台改版,并入淘宝开放平台中,我们的麻烦就开 ...

  3. 用原生js实现一个new方法

    首先写一个父类方法(包含参数name,age): function Person(name,age){ this.name = name; this.age = age; } new一个Person的 ...

  4. 判断json是否包含了每个键 PHP

    (1)可以用array_key_exists去判断object对象或array数组中是否含有某个键: (2)不可以用isset去判断判断object对象或array数组中是否含有某个键 $decode ...

  5. 业余草分享100套精选1000G架构师资料课程(超1T的IT学习资料免费送)

    业余草分享100套精选1000G架构师资料课程(超1T的IT学习资料免费送). 超过1024G的IT学习资料免费领取,你值得拥有! 领取资源方式,关注“业余草”公众号,回复对应的关键字 01.回复”我 ...

  6. Codeforces13E - Holes

    Portal Description \(n(n\leq10^5)\)个洞排成一条直线,第\(i\)个洞有力量值\(a_i\),当一个球掉进洞\(i\)时就会被立刻弹到\(i+a_i\),直到超出\( ...

  7. Raft论文学习笔记

    先附上论文链接  https://pdos.csail.mit.edu/6.824/papers/raft-extended.pdf 最近在自学MIT的6.824分布式课程,找到两个比较好的githu ...

  8. 关于.Net的知识和相关书籍

    a. DBCC DROPCLEANBUFFERS 清空缓存信息b. DBCC FREEPROCCACHE 从过程缓存中删除所有元素2. 引用两个和尚打水的故事,说明平时要注重积累,只有量变达到了才会形 ...

  9. 3.3 与Cache相关的PCI总线事务

    PCI总线规范定义了一系列与Cache相关的总线事务,以提高PCI设备与主存储器进行数据交换的效率,即DMA读写的效率.当PCI设备使用DMA方式向存储器进行读写操作时,一定需要经过HOST主桥,而H ...

  10. WebService之CXF注解之二(Service接口)

    ITeacherService.java: /** * @Title:ITeacherService.java * @Package:com.you.service * @Description:教师 ...