【iOS】—— Masonry源码学习(浅看,未完)

news2024/11/13 9:29:35

Masonry

文章目录

  • Masonry
    • NSLayoutConstraint用法
    • Masonry源码

Masonry在我们之前的学习中是一个非常有用的第三方库。
Masonry是一种基于Objective-C语言的轻量级布局框架,它可以简化iOS应用程序中的自动布局任务。Masonry提供了一个方便的API,可以编写更加简洁和易于阅读的代码来创建约束。使用Masonry,您可以通过链式调用方法来设置视图之间的约束关系,而无需直接操作NSLayoutConstraint对象。

简单来说,Masonry就是封装了NSLayoutConstraint对象
在学习源码之前,我们先来看看NSLayoutConstraint的用法:

NSLayoutConstraint用法

在 Objective-C 中,NSLayoutConstraint 是一种用于定义视图之间关系的类。它可以让开发者通过代码的方式来描述视图之间的布局约束,从而实现自动化布局。通过使用 NSLayoutConstraint,开发者可以使得 iOS 应用在不同尺寸和方向的设备上都能够呈现出良好的布局效果。

NSLayoutConstraint 可以用来描述视图距离、大小、比例等方面的约束条件,例如一个视图需要与另一个视图保持一定距离,或者两个视图需要保持相同的宽度和高度。

NSLayoutConstraint 的创建通常需要指定两个视图(或者一个视图和父视图)以及一个属性,即要约束的属性。然后,可以设置这个属性的值,以及关于这个属性的其他限制条件。最后,将该约束添加到对应的视图上,即可实现对视图之间布局的控制。

示例:

    // 创建父视图
    UIView *containerView = [UIView new];
    containerView.translatesAutoresizingMaskIntoConstraints = YES;
    containerView.backgroundColor = UIColor.yellowColor;
    containerView.frame = CGRectMake(100, 100, 200, 200);
    [self.view addSubview:containerView];

    // 创建子视图
    UIView *redView = [UIView new];
    redView.translatesAutoresizingMaskIntoConstraints = NO;
    redView.backgroundColor = UIColor.redColor;
    [containerView addSubview:redView];

    // 创建约束条件:view2 距离 view1 的四周都有 20 的间距
    NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem:redView
                                                                      attribute:NSLayoutAttributeRight
                                                                      relatedBy:NSLayoutRelationEqual
                                                                         toItem:containerView
                                                                      attribute:NSLayoutAttributeRight
                                                                     multiplier:1.0
                                                                       constant:-20];
    NSLayoutConstraint *constraint2 = [NSLayoutConstraint constraintWithItem:redView
                                                                      attribute:NSLayoutAttributeBottom
                                                                      relatedBy:NSLayoutRelationEqual
                                                                         toItem:containerView
                                                                      attribute:NSLayoutAttributeBottom
                                                                     multiplier:1.0
                                                                       constant:-20];
    NSLayoutConstraint *constraint3 = [NSLayoutConstraint constraintWithItem:redView
                                                                      attribute:NSLayoutAttributeLeft
                                                                      relatedBy:NSLayoutRelationEqual
                                                                         toItem:containerView
                                                                      attribute:NSLayoutAttributeLeft
                                                                     multiplier:1.0
                                                                       constant:20];
    NSLayoutConstraint *constraint4 = [NSLayoutConstraint constraintWithItem:redView
                                                                      attribute:NSLayoutAttributeTop
                                                                      relatedBy:NSLayoutRelationEqual
                                                                         toItem:containerView
                                                                      attribute:NSLayoutAttributeTop
                                                                     multiplier:1.0
                                                                       constant:20];

    // 将约束条件添加到视图上
    [self.view addConstraints:@[constraint1, constraint2, constraint3, constraint4]];

展示效果:
请添加图片描述

我们看到有一个UIView的属性:

translatesAutoresizingMaskIntoConstraints

translatesAutoresizingMaskIntoConstraints是一个布尔属性,用于设置是否自动将视图的AutoresizingMask转换为Autolayout约束。当该属性为true时,UIView的frame和bounds值可以通过直接修改来重新定义视图位置和大小,并且不会影响其Autolayout约束。但是,在使用Autolayout时,为了能够正确地响应任何约束变化,建议将该属性设置为false。

Masonry源码

Masonry中的类名字比较类似,很容易搞混淆,我们先来看看这几个常用的类以及他们之间的关系:

  • MASConstraint:这个类表示一个约束条件,它包含了一个视图和一个属性,以及相关的关系和乘数等信息。
  • MASViewConstraint:这是MASConstraint的子类,表示一个包含两个视图之间的约束条件。
  • MASCompositeConstraint:这个类表示多个约束条件的组合。它可以用来对一组视图应用相同的布局规则。
  • MASConstraintMaker:这个类是用来创建约束条件的入口点。它提供了一组类似于DSL的API,用于创建常见的约束条件,如等宽、等高、上下左右边距等。
  • MASLayoutConstraint:这个类是Masonry内部使用的私有类,它负责将MASConstraint对象转换成NSLayoutConstraint对象,并将其添加到视图上。
  • MASViewAttribute:是一个Masonry框架中的类,用于表示视图的特定属性。它可以用来创建和布局视图之间的约束。

请添加图片描述

一个最简单的Masonry:

    [view1 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.width.height.mas_equalTo(@10);
        make.centerX.mas_equalTo(self.view.mas_centerX);
        make.top.mas_equalTo(self.view.mas_top).offset(20);
    }];

我们点进去这个mas_makeConstraints方法:

//View+MASAdditions.h
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    //这个属性刚刚讲到过,所以用Masonry就可以不用设置这个属性了
    MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
    block(constraintMaker);
    return [constraintMaker install];
}

在该方法中调用constraintMaker的初始化方法,传给该方法要设置约束的view,生产maker对象,传给block回调出去,然后再调用maker的install方法。

//MASConstraintMaker
- (id)initWithView:(MAS_VIEW *)view {
    self = [super init];
    if (!self) return nil;
    
    self.view = view;
    self.constraints = NSMutableArray.new;
    
    return self;
}

initWithView:会记录下要设置约束的当前view,同时创建一个数组用来存储即将使用maker添加的约束。在传给mas_makeConstraints方法的block参数中,使用回调出来的maker进行一一添加约束。下面是使用make.width点语法后的全部内部调用过程:

// MASConstraintMaker
- (MASConstraint *)width {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeWidth];
}

- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
    return [self constraint:nil addConstraintWithLayoutAttribute:layoutAttribute];
}

- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
    // 根据约束属性和视图创建一个约束单元
    MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute];
    //创建约束,以约束单元作为约束的第一项
    MASViewConstraint *newConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute];
    if ([constraint isKindOfClass:MASViewConstraint.class]) {
        //replace with composite constraint
        // 如果是在已有约束的基础上再创建的约束,则将它们转换成一个 组合约束,并将原约束替换成该组合约束。
        NSArray *children = @[constraint, newConstraint];
        MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children];
        compositeConstraint.delegate = self;
        // 这里会将原来 make.width 添加的约束 替换成一个 组合约束(宽度约束 + 高度约束)
        [self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint];
        // 返回组合约束
        return compositeConstraint;
    }
    if (!constraint) {// 如果不是在已有约束的基础上再创建约束,则添加约束至列表
        newConstraint.delegate = self;// 注意这一步,会对 make.top.left 这种情形产生关键影响
        [self.constraints addObject:newConstraint];
    }
    return newConstraint;
}

在第二次设置约束时(.height)会进入不同的流程。注意上面提到的newConstraint.delegate设置代理:

//MAConstraint
- (MASConstraint *)height {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeHeight];
}
//MSViewConstraint
- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
    NSAssert(!self.hasLayoutRelation, @"Attributes should be chained before defining the constraint relation");
	//delegate是MASConstraintMaker
    return [self.delegate constraint:self addConstraintWithLayoutAttribute:layoutAttribute];
}
// MASConstraintMaker
//还是走到刚刚那个方法那里
- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {...}

接着来看看.mas_equalTo(@100)的流程:

// MASConstraint
#define mas_equalTo(...)                 equalTo(MASBoxValue((__VA_ARGS__)))
- (MASConstraint * (^)(id))equalTo {
    return ^id(id attribute) {
        // attribute 可能是 @100 类似的值,也可能是 view.mas_width等这样的
        return self.equalToWithRelation(attribute, NSLayoutRelationEqual);
    };
}
- (MASConstraint * (^)(id))mas_equalTo {
    return ^id(id attribute) {
        return self.equalToWithRelation(attribute, NSLayoutRelationEqual);
    };
}
// MASViewConstraint
- (MASConstraint * (^)(id, NSLayoutRelation))equalToWithRelation {
    return ^id(id attribute, NSLayoutRelation relation) {
        if ([attribute isKindOfClass:NSArray.class]) {//是数组(有多个约束)
            NSAssert(!self.hasLayoutRelation, @"Redefinition of constraint relation");
            NSMutableArray *children = NSMutableArray.new;
            for (id attr in attribute) {
                MASViewConstraint *viewConstraint = [self copy];
                viewConstraint.layoutRelation = relation;
                viewConstraint.secondViewAttribute = attr;// 设置约束第二项
                [children addObject:viewConstraint];
            }
            MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children];
            compositeConstraint.delegate = self.delegate;
            [self.delegate constraint:self shouldBeReplacedWithConstraint:compositeConstraint];
            return compositeConstraint;
        } else {//单个约束
            NSAssert(!self.hasLayoutRelation || self.layoutRelation == relation && [attribute isKindOfClass:NSValue.class], @"Redefinition of constraint relation");
            self.layoutRelation = relation;
            self.secondViewAttribute = attribute;// 设置约束第二项
            return self;
        }
    };
}
// 设置约束第二项
- (void)setSecondViewAttribute:(id)secondViewAttribute {
    if ([secondViewAttribute isKindOfClass:NSValue.class]) {   //数字等
        [self setLayoutConstantWithValue:secondViewAttribute];
    } else if ([secondViewAttribute isKindOfClass:MAS_VIEW.class]) {    //frame等
        _secondViewAttribute = [[MASViewAttribute alloc] initWithView:secondViewAttribute layoutAttribute:self.firstViewAttribute.layoutAttribute];
    } else if ([secondViewAttribute isKindOfClass:MASViewAttribute.class]) {   //约束对象
        _secondViewAttribute = secondViewAttribute;
    } else {
        NSAssert(NO, @"attempting to add unsupported attribute: %@", secondViewAttribute);
    }
}
// MASConstraint
- (void)setLayoutConstantWithValue:(NSValue *)value {
    if ([value isKindOfClass:NSNumber.class]) {
        self.offset = [(NSNumber *)value doubleValue];
    } else if (strcmp(value.objCType, @encode(CGPoint)) == 0) {
        CGPoint point;
        [value getValue:&point];
        self.centerOffset = point;
    } else if (strcmp(value.objCType, @encode(CGSize)) == 0) {
        CGSize size;
        [value getValue:&size];
        self.sizeOffset = size;
    } else if (strcmp(value.objCType, @encode(MASEdgeInsets)) == 0) {
        MASEdgeInsets insets;
        [value getValue:&insets];
        self.insets = insets;
    } else {
        NSAssert(NO, @"attempting to set layout constant with unsupported value: %@", value);
    }
}

// MASViewConstraint
- (void)setOffset:(CGFloat)offset {
    self.layoutConstant = offset;       // 设置约束常量
}
- (void)setSizeOffset:(CGSize)sizeOffset {
    NSLayoutAttribute layoutAttribute = self.firstViewAttribute.layoutAttribute;
    switch (layoutAttribute) {
        case NSLayoutAttributeWidth:
            self.layoutConstant = sizeOffset.width;
            break;
        case NSLayoutAttributeHeight:
            self.layoutConstant = sizeOffset.height;
            break;
        default:
            break;
    }
}
- (void)setCenterOffset:(CGPoint)centerOffset {
    NSLayoutAttribute layoutAttribute = self.firstViewAttribute.layoutAttribute;
    switch (layoutAttribute) {
        case NSLayoutAttributeCenterX:
            self.layoutConstant = centerOffset.x;
            break;
        case NSLayoutAttributeCenterY:
            self.layoutConstant = centerOffset.y;
            break;
        default:
            break;
    }
}
- (void)setInsets:(MASEdgeInsets)insets {
    NSLayoutAttribute layoutAttribute = self.firstViewAttribute.layoutAttribute;
    switch (layoutAttribute) {
        case NSLayoutAttributeLeft:
        case NSLayoutAttributeLeading:
            self.layoutConstant = insets.left;
            break;
        case NSLayoutAttributeTop:
            self.layoutConstant = insets.top;
            break;
        case NSLayoutAttributeBottom:
            self.layoutConstant = -insets.bottom;
            break;
        case NSLayoutAttributeRight:
        case NSLayoutAttributeTrailing:
            self.layoutConstant = -insets.right;
            break;
        default:
            break;
    }
}

再看如果约束对象是一个控件(mas_equalTo(self.view.mas_top)),那么就会走进下面的这段代码:

else if ([secondViewAttribute isKindOfClass:MASViewAttribute.class]) {
	_secondViewAttribute = secondViewAttribute;
} 

另外,后面的 offset 方法做了一步额外的操作:

// MASConstraint
- (MASConstraint * (^)(CGFloat))offset {
    return ^id(CGFloat offset){
        self.offset = offset;
        return self;
    };
}
- (void)setOffset:(CGFloat)offset {
    self.layoutConstant = offset;
}

回到前面,block执行结束之后,调用了[constraintMaker install],下面看一下install方法的实现:

- (NSArray *)install {
    // 只有在 mas_remakeConstraints 时,removeExisting 才为 YES
    if (self.removeExisting) {
        // 此时,需要先删除所有的约束
        NSArray *installedConstraints = [MASViewConstraint installedConstraintsForView:self.view];
        for (MASConstraint *constraint in installedConstraints) {
            [constraint uninstall];
        }
    }
    // 添加约束
    NSArray *constraints = self.constraints.copy;
    for (MASConstraint *constraint in constraints) {
        // 设置约束的 updateExisting 属性
        // 只有在 mas_updateConstraints 时,updateExisting 才为 YES
        constraint.updateExisting = self.updateExisting;
        [constraint install];
    }
    // 清空 constraints 数组缓存
    [self.constraints removeAllObjects];
    return constraints;
}

install 方法内部会对 constraints 列表中的所有约束依次执行各自的 install 方法来添加约束。我们来看一下约束的 install 方法:

// MASCompositeConstraint
- (void)install {
    for (MASConstraint *constraint in self.childConstraints) {
        constraint.updateExisting = self.updateExisting;
        [constraint install];
    }
}

// MASViewConstraint
- (void)install {
    // 约束是否已被添加
    if (self.hasBeenInstalled) {
        return;
    }
    // 如果约束支持 isActive 方法,且 self.layoutConstraint 有值了
    if ([self supportsActiveProperty] && self.layoutConstraint) {
        if (@available(iOS 8.0, *)) {
            self.layoutConstraint.active = YES;
        } else {
            // Fallback on earlier versions
        }
        [self.firstViewAttribute.view.mas_installedConstraints addObject:self];
        return;
    }
    
    MAS_VIEW *firstLayoutItem = self.firstViewAttribute.item;
    NSLayoutAttribute firstLayoutAttribute = self.firstViewAttribute.layoutAttribute;
    MAS_VIEW *secondLayoutItem = self.secondViewAttribute.item;
    NSLayoutAttribute secondLayoutAttribute = self.secondViewAttribute.layoutAttribute;

    // alignment attributes must have a secondViewAttribute
    // therefore we assume that is refering to superview
    //对齐属性必须具有第二个ViewAttribute。因此我们假设它指的是超视图
    // eg make.left.equalTo(@10)
    if (!self.firstViewAttribute.isSizeAttribute && !self.secondViewAttribute) {
        secondLayoutItem = self.firstViewAttribute.view.superview;
        secondLayoutAttribute = firstLayoutAttribute;
    }
    // 生成一个 NSLayoutConstraint
    MASLayoutConstraint *layoutConstraint
        = [MASLayoutConstraint constraintWithItem:firstLayoutItem
                                        attribute:firstLayoutAttribute
                                        relatedBy:self.layoutRelation
                                           toItem:secondLayoutItem
                                        attribute:secondLayoutAttribute
                                       multiplier:self.layoutMultiplier
                                         constant:self.layoutConstant];
    
    layoutConstraint.priority = self.layoutPriority;
    layoutConstraint.mas_key = self.mas_key;
    // 确定约束layoutConstraint 的约束层级(即要被添加到的位置)
    if (self.secondViewAttribute.view) {
        MAS_VIEW *closestCommonSuperview = [self.firstViewAttribute.view mas_closestCommonSuperview:self.secondViewAttribute.view];
        NSAssert(closestCommonSuperview,
                 @"couldn't find a common superview for %@ and %@",
                 self.firstViewAttribute.view, self.secondViewAttribute.view);
        self.installedView = closestCommonSuperview;
    } else if (self.firstViewAttribute.isSizeAttribute) {
        self.installedView = self.firstViewAttribute.view;
    } else {
        self.installedView = self.firstViewAttribute.view.superview;
    }

    MASLayoutConstraint *existingConstraint = nil;
    if (self.updateExisting) {
        existingConstraint = [self layoutConstraintSimilarTo:layoutConstraint];
    }
    if (existingConstraint) {
        // just update the constant
        // 约束存在,则更新constant值
        existingConstraint.constant = layoutConstraint.constant;
        self.layoutConstraint = existingConstraint;
    } else {
        // 约束不存在,则在该位置添加约束
        [self.installedView addConstraint:layoutConstraint];
        self.layoutConstraint = layoutConstraint;
        [firstLayoutItem.mas_installedConstraints addObject:self];
    }
}

无论是 MASCompositeConstraint 还是 MASViewConstraint,本质上还是调用 MASViewConstraint 的 install 方法。该方法根据 MASViewConstraint 的各个属性创建一个原生的约束(NSLayoutConstraint 类型),并在定位约束层级后,将约束添加到相应层级的视图上。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kubernetes Service、Ingress

Service(4层负载均衡器) 1、K8S 可以保证任意 Pod 挂掉时自动从任意节点启动一个新的Pod进行代替,以及某个Pod超负载时动态对Pod进行扩容。每当 Pod 发生变化时其 IP地址也会发生变化,且Pod只有在K8S集群内部才可以被访问&#xf…

Flink高手之路4-Flink流批一体

文章目录 Flink高手之路4-Flink流批一体API开发一、流批一体相关的概念1.数据的时效性2.流处理和批处理1)批处理2)流处理3)两者对比 3.流批一体API4.流批一体的编程模型 二、Data Source1.预定义的Source1)基于集合的Sources(1)API(2)演示 2)基于文件的Source(1)API(2)演示 3)基…

2023.4.19 + 4.20

文章目录 String类1:介绍:2:String类实现了很多的接口:3;String类常用构造器4:不同方式创建String类对象的区别(1)直接赋值的方式(2)常规new的方式&#xff0…

【筛质数】——朴素筛,埃式筛,欧拉筛

题目描述: 题目分析: 这道题可以用,朴素筛,埃氏筛,欧拉筛来写。 普通筛: 时间复杂度:O(n logn) 时间复杂度太高,会超时的!!(9/10) #…

Keil5----显示空白符和设置使用空白格表示Tab键

一、Keil5界面----显示空白符 首先打开Keil5-MDK界面,然后按照下面步骤操作。 步骤1:点击 Edit(编辑),然后点击 Configuration(配置) 步骤2:勾选 View White Spaces(查看空白) 步骤3:显示设置后的结果 具体显示结果分…

Git添加SSH密钥本地仓库上传远程GitHub库

1、前言 现在想要从本地设备将本地仓库上传到GitHub上需要用到SSH密钥,接下来讲解大致的步骤,本文默认读者已经掌握基本的Git知识 2、详细步骤 2.1 创建密钥 在本地项目仓库根目录下,输入下面的命令: ssh-keygen -t rsa命令输…

深度学习 Day 31——YOLOv5-Backbone模块实现

深度学习 Day 31——YOLOv5-Backbone模块实现 文章目录 深度学习 Day 31——YOLOv5-Backbone模块实现一、前言二、我的环境三、什么是YOLOv5-Backbone模块?四、搭建包含Backbone模块的模型1、模型整体代码2、模型每一部分详解3、模型详情 五、模型训练六、最终结果1…

计算机|网页设计 |七大罪动漫主题|作品分享

文章目录 一、主题介绍二、截图展示三、源代码获取 一、主题介绍 计算机|网页设计 |七大罪动漫主题|作品分享 一个关于七大罪动漫主题的网页设计。共4页 图片文字都可修改! 二、截图展示 三、源代码获取 本次的分享就到这里啦&…

双指针【算法推导、背模板】——最长连续不重复子序列

799. 最长连续不重复子序列 - AcWing题库 通常情况双指针就是需要将O(N^2^)&#xff0c;利用某些单调性质实现O(N) 通用代码模板 for(int i 0 , j 0; i < n ; i ){while(j < i && check(i , j ) ) j ;// 需要处理的逻辑 }check判断是否构成 算法推导 题目中…

LLM总结(持续更新中)

引言 当前LLM模型火出天际&#xff0c;但是做事还是需要脚踏实地。此文只是日常学习LLM&#xff0c;顺手整理所得。本篇博文更多侧重对话、问答类LLM上&#xff0c;其他方向&#xff08;代码生成&#xff09;这里暂不涉及&#xff0c;可以去看综述来了解。 之前LLM模型梳理 …

微服务---RabbitMQ与SpringAMQP基本使用

RabbitMQ 1.初识MQ 1.1.同步和异步通讯 微服务间通讯有同步和异步两种方式&#xff1a; 同步通讯&#xff1a;就像打电话&#xff0c;需要实时响应。 异步通讯&#xff1a;就像发邮件&#xff0c;不需要马上回复。 两种方式各有优劣&#xff0c;打电话可以立即得到响应&am…

OpenCV实例(四)手写数字识别

OpenCV实例&#xff08;四&#xff09;手写数字识别 1.基本原理2.实现步骤2.1数据准备2.2计算匹配值2.3获取最佳匹配值及对应模板2.4获取最佳匹配模板对应的数字2.5输出识别结果 3.代码实例 作者&#xff1a;Xiou 1.基本原理 使用模板匹配的方式实现手写数字识别&#xff0c;…

2023/4/20总结

项目 网上关于listview的资料太少了&#xff0c;在网上的那些资料里面&#xff0c;了解到以下这些。 如果希望listview后期能更改或者更新&#xff0c;那么需要使用到 ObservableList 它可以观察到&#xff0c;listview的改动。 需要特别注意一点的是&#xff1a;写俩者的…

如何发布自己的 npm 包?

一. 准备工作 1. 注册 npm 账号 还没有 npm 账号&#xff1f;去官网注册&#xff1a; https://www.npmjs.com/ 需要记住用户名、密码、邮箱 2. 查看本地 npm 镜像&#xff0c;如果不是默认的&#xff0c;需要改回来 npm config get registry重置镜像路径 npm config set r…

vulstack ATTCK(三)靶场

0x00环境搭建 两种形式 1.添加vmare2网卡&#xff0c;修改vmare2网卡的地址为192.168.93.0网段&#xff0c;注意不要在连接到主机适配器上打勾&#xff0c;这样会使本机也可以访问此电脑&#xff0c;5台机器都换成vmare2即可&#xff0c;第一台出网的centos在添加另一张nat网卡…

Docker容器---数据卷 数据容器

Docker容器---数据卷 数据容器 一、数据卷概述1、数据卷2、数据卷原理3、数据卷作用 二、数据卷容器1、数据卷容器作用2、创建数据卷容器 三、容器互联1、创建并运行源容器取名web12、创建并运行接收容器取名web2 一、数据卷概述 管理 Docker 容器中数据主要有两种方式&#x…

社科院与杜兰大学中外合作办学金融管理硕士项目——比起过往,前路更值得期待

当结束一天工作陷入沉思时&#xff0c;你有没有特别遗憾的事情呢&#xff0c;人生有太多的不确定性&#xff0c;比起过往&#xff0c;未知的人生更值得我们期待。与其懊恼没完成的遗憾&#xff0c;不如珍惜当下&#xff0c;努力创造未来。人生没有太晚的开始&#xff0c;在职读…

frp内网穿透——以连接到校园内网的服务器为例

有时候想摸鱼不去实验室&#xff0c;在宿舍就直接连接到实验室的GPU服务器。奈何服务器在校园网内部&#xff0c;外网无法直接直接访问。此时需要手动搭一个跳板机&#xff0c;来连接到内网的GPU服务器&#xff0c;这一过程怎么做到呢&#xff1f;我们可以使用frp内网穿透工具&…

Seata:连接数据与应用

作者&#xff1a;季敏&#xff08;清铭&#xff09;Seata 开源社区创始人&#xff0c;分布式事务团队负责人。 本文主要介绍分布式事务从内部到商业化和开源的演进历程&#xff0c;Seata 社区当前进展和未来规划。 Seata 是一款开源的分布式事务解决方案&#xff0c;旨在为现…

Java基础(十八):java比较器、系统相关类、数学相关类

Java基础系列文章 Java基础(一)&#xff1a;语言概述 Java基础(二)&#xff1a;原码、反码、补码及进制之间的运算 Java基础(三)&#xff1a;数据类型与进制 Java基础(四)&#xff1a;逻辑运算符和位运算符 Java基础(五)&#xff1a;流程控制语句 Java基础(六)&#xff1…