iOS--编译

news2024/11/26 1:30:38

前言

iOS 开发中使用的是编译语言,所谓编译语言是在执行的时候,必须先通过编译器生成机器码,机器码可以直接在CPU上执行,所以执行效率较高。他是使用 Clang / LLVM 来编译的。LLVM是一个模块化和可重用的编译器和工具链技术的集合,Clang 是 LLVM 的子项目,是 C,C++ 和 Objective-C 编译器,目的是提供惊人的快速编译。下面我们来看看编译过程,总的来说编译过程分为几个阶段: 预处理 -> 词法分析 -> 语法分析 -> 静态分析 -> 生成中间代码和优化 -> 汇编 -> 链接

具体过程

预处理

我们以一个实际例子来看看,预处理的过程,源码:

#import <UIKit/UIKit.h>
#import "AppDelegate.h"

int main(int argc, char * argv[]) {
    NSString * appDelegateClassName;
    @autoreleasepool {
        // Setup code that might create autoreleased objects goes here.
        appDelegateClassName = NSStringFromClass([AppDelegate class]);
    }
    return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}

使用终端到main.m所在文件夹,使用命令:clang -E main.m,结果如下:

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (readonly, strong) NSPersistentContainer *persistentContainer;

- (void)saveContext;


@end
# 10 "main.m" 2

int main(int argc, char * argv[]) {
    NSString * appDelegateClassName;
    @autoreleasepool {

        appDelegateClassName = NSStringFromClass([AppDelegate class]);
    }
    return UIApplicationMain(argc, argv, ((void *)0), appDelegateClassName);
}

请添加图片描述
也可以使用Xcode的Product->Perform Action -> Preprocess得到相同的结果请添加图片描述
请添加图片描述
这一步编译器所做的处理是:

  • 宏替换
    在源码中使用的宏定义会被替换为对应#define的内容)
    建议大家不要在需要预处理的代码中加入内联代码逻辑。
  • 头文件引入(#include,#import)
    使用对应文件.h的内容替换这一行的内容,所以尽量减少头文件中的#import,使用@class替代,把#import放到.m文件中。
  • 处理条件编译指令 (#if,#else,#endif)

词法解析

使用clang -Xclang -dump-tokens main.m词法分析结果如下:

int 'int'	 [StartOfLine]	Loc=<main.m:14:1>
identifier 'main'	 [LeadingSpace]	Loc=<main.m:14:5>
l_paren '('		Loc=<main.m:14:9>
int 'int'		Loc=<main.m:14:10>
identifier 'argc'	 [LeadingSpace]	Loc=<main.m:14:14>
comma ','		Loc=<main.m:14:18>
char 'char'	 [LeadingSpace]	Loc=<main.m:14:20>
star '*'	 [LeadingSpace]	Loc=<main.m:14:25>
identifier 'argv'	 [LeadingSpace]	Loc=<main.m:14:27>
l_square '['		Loc=<main.m:14:31>
r_square ']'		Loc=<main.m:14:32>
r_paren ')'		Loc=<main.m:14:33>
l_brace '{'	 [LeadingSpace]	Loc=<main.m:14:35>
at '@'	 [StartOfLine] [LeadingSpace]	Loc=<main.m:15:5>
identifier 'autoreleasepool'		Loc=<main.m:15:6>
l_brace '{'	 [LeadingSpace]	Loc=<main.m:15:22>
identifier 'NSLog'	 [StartOfLine] [LeadingSpace]	Loc=<main.m:17:9>
l_paren '('		Loc=<main.m:17:14>
at '@'		Loc=<main.m:17:15>
string_literal '"%d"'		Loc=<main.m:17:16>
comma ','		Loc=<main.m:17:20>
numeric_constant '1'		Loc=<main.m:17:21 <Spelling=main.m:12:16>>
r_paren ')'		Loc=<main.m:17:27>
semi ';'		Loc=<main.m:17:28>
return 'return'	 [StartOfLine] [LeadingSpace]	Loc=<main.m:19:9>
identifier 'UIApplicationMain'	 [LeadingSpace]	Loc=<main.m:19:16>
l_paren '('		Loc=<main.m:19:33>
identifier 'argc'		Loc=<main.m:19:34>
comma ','		Loc=<main.m:19:38>
identifier 'argv'	 [LeadingSpace]	Loc=<main.m:19:40>
comma ','		Loc=<main.m:19:44>
identifier 'nil'	 [LeadingSpace]	Loc=<main.m:19:46>
comma ','		Loc=<main.m:19:49>
identifier 'NSStringFromClass'	 [LeadingSpace]	Loc=<main.m:19:51>
l_paren '('		Loc=<main.m:19:68>
l_square '['		Loc=<main.m:19:69>
identifier 'AppDelegate'		Loc=<main.m:19:70>
identifier 'class'	 [LeadingSpace]	Loc=<main.m:19:82>
r_square ']'		Loc=<main.m:19:87>
r_paren ')'		Loc=<main.m:19:88>
r_paren ')'		Loc=<main.m:19:89>
semi ';'		Loc=<main.m:19:90>
r_brace '}'	 [StartOfLine] [LeadingSpace]	Loc=<main.m:20:5>
r_brace '}'	 [StartOfLine]	Loc=<main.m:21:1>
eof ''		Loc=<main.m:21:2>

这一步把源文件中的代码转化为特殊的标记流,源码被分割成一个一个的字符和单词,在行尾Loc中都标记出了源码所在的对应源文件和具体行数,方便在报错时定位问题。

语法分析

执行 clang 命令 clang -Xclang -ast-dump -fsyntax-only maim.m得到如下结果:

|-FunctionDecl 0x7f9fa085a9b8 <main.m:14:1, line:21:1> line:14:5 main 'int (int, char **)'
| |-ParmVarDecl 0x7f9fa085a788 <col:10, col:14> col:14 used argc 'int'
| |-ParmVarDecl 0x7f9fa085a8a0 <col:20, col:32> col:27 used argv 'char **':'char **'
| `-CompoundStmt 0x7f9fa1002240 <col:35, line:21:1>
|   `-ObjCAutoreleasePoolStmt 0x7f9fa1002230 <line:15:5, line:20:5>
|     `-CompoundStmt 0x7f9fa1002210 <line:15:22, line:20:5>
|       `-CallExpr 0x7f9fa085aec0 <line:17:9, col:27> 'void'
|         |-ImplicitCastExpr 0x7f9fa085aea8 <col:9> 'void (*)(id, ...)' <FunctionToPointerDecay>
|         | `-DeclRefExpr 0x7f9fa085ac90 <col:9> 'void (id, ...)' Function 0x7f9fa085ab38 'NSLog' 'void (id, ...)'
|         |-ImplicitCastExpr 0x7f9fa085aef8 <col:15, col:16> 'id':'id' <BitCast>
|         | `-ObjCStringLiteral 0x7f9fa085ae08 <col:15, col:16> 'NSString *'
|         |   `-StringLiteral 0x7f9fa085acf8 <col:16> 'char [3]' lvalue "%d"
|         `-IntegerLiteral 0x7f9fa085ae28 <line:12:16> 'int' 1
|-FunctionDecl 0x7f9fa085ab38 <line:17:9> col:9 implicit used NSLog 'void (id, ...)' extern
| |-ParmVarDecl 0x7f9fa085abd0 <<invalid sloc>> <invalid sloc> 'id':'id'
| `-FormatAttr 0x7f9fa085ac38 <col:9> Implicit NSString 1 2
|-FunctionDecl 0x7f9fa085af60 <<invalid sloc>> line:19:16 implicit used UIApplicationMain 'int ()'
`-FunctionDecl 0x7f9fa085b098 <<invalid sloc>> col:51 implicit used NSStringFromClass 'int ()'

这一步是把词法分析生成的标记流,解析成一个抽象语法树(abstract syntax tree – AST),同样地,在这里面每一节点也都标记了其在源码中的位置。

静态分析

把源码转化为抽象语法树之后,编译器就可以对这个树进行分析处理。静态分析会对代码进行错误检查,如出现方法被调用但是未定义、定义但是未使用的变量等,以此提高代码质量。当然,还可以通过使用 Xcode 自带的静态分析工具(Product -> Analyze)
把源码转化为抽象语法树之后,编译器就可以对这个树进行分析处理。静态分析会对代码进行错误检查,如出现方法被调用但是未定义、定义但是未使用的变量等,以此提高代码质量。当然,还可以通过使用 Xcode 自带的静态分析工具(Product -> Analyze)

  • 类型检查
    在此阶段clang会做检查,最常见的是检查程序是否发送正确的消息给正确的对象,是否在正确的值上调用了正常函数。如果你给一个单纯的 NSObject* 对象发送了一个 hello 消息,那么 clang 就会报错,同样,给属性设置一个与其自身类型不相符的对象,编译器会给出一个可能使用不正确的警告。

一般会把类型分为两类:动态的和静态的。动态的在运行时做检查,静态的在编译时做检查。以往,编写代码时可以向任意对象发送任何消息,在运行时,才会检查对象是否能够响应这些消息。由于只是在运行时做此类检查,所以叫做动态类型。
至于静态类型,是在编译时做检查。当在代码中使用 ARC 时,编译器在编译期间,会做许多的类型检查:因为编译器需要知道哪个对象该如何使用。

  • 其他分析
    ObjCUnusedIVarsChecker.cpp是用来检查是否有定义了,但是从未使用过的变量。( This file defines a CheckObjCUnusedIvars, a checker that analyzes an Objective-C class's interface/implementation to determine if it has any ivars that are never accessed.)
    ObjCSelfInitChecker.cpp是检查在 你的初始化方法中中调用 self 之前,是否已经调用[self initWith...][super init]了(
    This checks initialization methods to verify that they assign 'self' to the result of an initialization call (e.g. [super init], or [self initWith..]) before using 'self' or any instance variable.)。

中间代码生成和优化

LLVM IR有3种表示形式,但本质上是等价的。

text:便于阅读的文本格式,类似于汇编语言,拓展名 .ll
memory:内存格式
bitcode:二进制格式,拓展名 .bc
我们对下面代码使用clang -O3 -S -emit-llvm main.m -o main.ll,生成main.ll

#import <Foundation/Foundation.h>
#define a1 1

int sum(int a, int b) {
    int c = a + b;
    return c;
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        int a = 5;
        NSLog(@"%d", sum(a1, a));
    }
    return 0;
}
; ModuleID = 'main.m'
source_filename = "main.m"
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
target triple = "arm64-apple-macosx12.0.0"

%struct.__NSConstantString_tag = type { i32*, i32, i8*, i64 }

@__CFConstantStringClassReference = external global [0 x i32]
@.str = private unnamed_addr constant [14 x i8] c"Hello, World!\00", section "__TEXT,__cstring,cstring_literals", align 1
@_unnamed_cfstring_ = private global %struct.__NSConstantString_tag { i32* getelementptr inbounds ([0 x i32], [0 x i32]* @__CFConstantStringClassReference, i32 0, i32 0), i32 1992, i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str, i32 0, i32 0), i64 13 }, section "__DATA,__cfstring", align 8 #0
@.str.1 = private unnamed_addr constant [3 x i8] c"%d\00", section "__TEXT,__cstring,cstring_literals", align 1
@_unnamed_cfstring_.2 = private global %struct.__NSConstantString_tag { i32* getelementptr inbounds ([0 x i32], [0 x i32]* @__CFConstantStringClassReference, i32 0, i32 0), i32 1992, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.1, i32 0, i32 0), i64 2 }, section "__DATA,__cfstring", align 8 #0

; Function Attrs: norecurse nounwind readnone ssp uwtable willreturn
define i32 @sum(i32 %0, i32 %1) local_unnamed_addr #1 {
  %3 = add nsw i32 %1, %0
  ret i32 %3
}

; Function Attrs: ssp uwtable
define i32 @main(i32 %0, i8** nocapture readnone %1) local_unnamed_addr #2 {
  %3 = tail call i8* @llvm.objc.autoreleasePoolPush() #3
  notail call void (i8*, ...) @NSLog(i8* bitcast (%struct.__NSConstantString_tag* @_unnamed_cfstring_ to i8*))
  notail call void (i8*, ...) @NSLog(i8* bitcast (%struct.__NSConstantString_tag* @_unnamed_cfstring_.2 to i8*), i32 6)
  tail call void @llvm.objc.autoreleasePoolPop(i8* %3)
  ret i32 0
}

; Function Attrs: nounwind
declare i8* @llvm.objc.autoreleasePoolPush() #3

declare void @NSLog(i8*, ...) local_unnamed_addr #4

; Function Attrs: nounwind
declare void @llvm.objc.autoreleasePoolPop(i8*) #3

attributes #0 = { "objc_arc_inert" }
attributes #1 = { norecurse nounwind readnone ssp uwtable willreturn "disable-tail-calls"="false" "frame-pointer"="non-leaf" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "probe-stack"="__chkstk_darwin" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.5a,+zcm,+zcz" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { ssp uwtable "disable-tail-calls"="false" "frame-pointer"="non-leaf" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "probe-stack"="__chkstk_darwin" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.5a,+zcm,+zcz" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #3 = { nounwind }
attributes #4 = { "disable-tail-calls"="false" "frame-pointer"="non-leaf" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "probe-stack"="__chkstk_darwin" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.5a,+zcm,+zcz" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11}
!llvm.ident = !{!12}

!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 12, i32 1]}
!1 = !{i32 1, !"Objective-C Version", i32 2}
!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
!6 = !{i32 1, !"wchar_size", i32 4}
!7 = !{i32 1, !"branch-target-enforcement", i32 0}
!8 = !{i32 1, !"sign-return-address", i32 0}
!9 = !{i32 1, !"sign-return-address-all", i32 0}
!10 = !{i32 1, !"sign-return-address-with-bkey", i32 0}
!11 = !{i32 7, !"PIC Level", i32 2}
!12 = !{!"Apple clang version 13.0.0 (clang-1300.0.29.30)"}

接下来 LLVM 会对代码进行编译优化,例如针对全局变量优化、循环优化、尾递归优化等,最后输出汇编代码。使用xcrun clang -S -o - main.m | open -f生成汇编代码:

	.section	__TEXT,__text,regular,pure_instructions
	.build_version macos, 12, 0	sdk_version 12, 1
	.globl	_sum                            ; -- Begin function sum
	.p2align	2
_sum:                                   ; @sum
	.cfi_startproc
; %bb.0:
	sub	sp, sp, #16                     ; =16
	.cfi_def_cfa_offset 16
	str	w0, [sp, #12]
	str	w1, [sp, #8]
	ldr	w8, [sp, #12]
	ldr	w9, [sp, #8]
	add	w8, w8, w9
	str	w8, [sp, #4]
	ldr	w0, [sp, #4]
	add	sp, sp, #16                     ; =16
	ret
	.cfi_endproc
                                        ; -- End function
	.globl	_main                           ; -- Begin function main
	.p2align	2
_main:                                  ; @main
	.cfi_startproc
; %bb.0:
	sub	sp, sp, #64                     ; =64
	stp	x29, x30, [sp, #48]             ; 16-byte Folded Spill
	add	x29, sp, #48                    ; =48
	.cfi_def_cfa w29, 16
	.cfi_offset w30, -8
	.cfi_offset w29, -16
	mov	w8, #0
	str	w8, [sp, #24]                   ; 4-byte Folded Spill
	stur	wzr, [x29, #-4]
	stur	w0, [x29, #-8]
	stur	x1, [x29, #-16]
	bl	_objc_autoreleasePoolPush
	str	x0, [sp, #16]                   ; 8-byte Folded Spill
	adrp	x0, l__unnamed_cfstring_@PAGE
	add	x0, x0, l__unnamed_cfstring_@PAGEOFF
	bl	_NSLog
	mov	w8, #5
	stur	w8, [x29, #-20]
	ldur	w1, [x29, #-20]
	mov	w0, #1
	bl	_sum
	mov	x10, x0
	adrp	x0, l__unnamed_cfstring_.2@PAGE
	add	x0, x0, l__unnamed_cfstring_.2@PAGEOFF
	mov	x9, sp
                                        ; implicit-def: $x8
	mov	x8, x10
	str	x8, [x9]
	bl	_NSLog
	ldr	x0, [sp, #16]                   ; 8-byte Folded Reload
	bl	_objc_autoreleasePoolPop
	ldr	w0, [sp, #24]                   ; 4-byte Folded Reload
	ldp	x29, x30, [sp, #48]             ; 16-byte Folded Reload
	add	sp, sp, #64                     ; =64
	ret
	.cfi_endproc
                                        ; -- End function
	.section	__TEXT,__cstring,cstring_literals
l_.str:                                 ; @.str
	.asciz	"Hello, World!"

	.section	__DATA,__cfstring
	.p2align	3                               ; @_unnamed_cfstring_
l__unnamed_cfstring_:
	.quad	___CFConstantStringClassReference
	.long	1992                            ; 0x7c8
	.space	4
	.quad	l_.str
	.quad	13                              ; 0xd

	.section	__TEXT,__cstring,cstring_literals
l_.str.1:                               ; @.str.1
	.asciz	"%d"

	.section	__DATA,__cfstring
	.p2align	3                               ; @_unnamed_cfstring_.2
l__unnamed_cfstring_.2:
	.quad	___CFConstantStringClassReference
	.long	1992                            ; 0x7c8
	.space	4
	.quad	l_.str.1
	.quad	2                               ; 0x2

	.section	__DATA,__objc_imageinfo,regular,no_dead_strip
L_OBJC_IMAGE_INFO:
	.long	0
	.long	64

.subsections_via_symbols

看前面几行:

	.section	__TEXT,__text,regular,pure_instructions
	.build_version macos, 12, 0	sdk_version 12, 1
	.globl	_sum                            ; -- Begin function sum
	.p2align	2

他们是汇编指令而不是汇编代码。

.section指令指定了接下来会执行哪一个段
.globl指令说明_main是一个外部符号。这就是我们的main()函数。这个函数对外部是可见的,因为系统要调用它来运行可执行文件。
.p2align指令指出了后面代码的对齐方式。在我们的代码中,后面的代码会按照 16(2^4) 字节对齐,如果需要的话,用 0x90 补齐。

汇编

在这一阶段,汇编器将上一步生成的可读的汇编代码转化为机器代码。最终产物就是 以 .o 结尾的目标文件。使用Xcode构建的程序会在DerivedData目录中找到这个文件。

链接

这一阶段是将上个阶段生成的目标文件和引用的静态库链接起来,最终生成可执行文件,链接器解决了目标文件和库之间的链接。
可执行文件类型为 Mach-O 类型,在 MAC OS 和 iOS 平台的可执行文件都是这种类型。因为我使用的是模拟器,所以处理器指令集为 x86_64。
至此,编译过程结束。

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

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

相关文章

Tomcat之配置文件详解

Tomcat 目录 安装好 Tomcat 后&#xff0c;打开它的文件夹&#xff0c;可以看到以下目录 bin:存放各种启动、关闭和其它程序的脚本 conf:配置文件及相关数据文件存放的目录 lib:Tomcat 使用的库文件存放的目录&#xff0c;如存放 Servlet 规范的 API logs:默认日志文件存放…

centos 配置好网络后无法ping 通百度

问题&#xff1a; ping 自己配置的ip地址能够ping通&#xff0c;ping 连接的WiFi &#xff08;可以上外网&#xff09;地址也能ping通&#xff0c;但是ping www.baidu.com 却ping不同&#xff1b; 配置 处理方法&#xff1a; 我的虚拟机开通了三张网卡&#xff0c;150段…

更新NGINX域名证书文件

背景&#xff1a; 由于域名正式认证即将要到期&#xff0c;需要更新基于nginx的域名证书文件。 一、更新nginx域名证书文件 1、查看对应域名使用的正式文件名 # 查看使用的域名证书文件 # 我的环境配置https的nginx相关配置文件是&#xff1a;ierp_https.confcat /usr/loca…

Vue3+Vite+Pinia+Naive后台管理系统搭建之二:scss 的安装和使用

前言 如果对 vue3 的语法不熟悉的&#xff0c;可以移步 Vue3.0 基础入门&#xff0c;快速入门。 1. 安装依赖 yarn add sass -D // or npm install sass -D 2. 页面样式初始化 reset.scss /* 新建 src/assets/style/reset.scss */ /* 页面样式初始化 */ html, body, div, s…

前端Vue自定义水平步骤条组件

随着技术的发展&#xff0c;开发的复杂度也越来越高&#xff0c;传统开发方式将一个系统做成了整块应用&#xff0c;经常出现的情况就是一个小小的改动或者一个小功能的增加可能会引起整体逻辑的修改&#xff0c;造成牵一发而动全身。 通过组件化开发&#xff0c;可以有效实现…

edk2 security boot校验流程

edk2整体架构 关于安全校验的核心逻辑 Code\Edk2\MdeModulePkg\Universal\SecurityStubDxe\SecurityStub.c Status gBS->InstallMultipleProtocolInterfaces (&mSecurityArchProtocolHandle,&gEfiSecurity2ArchProtocolGuid,&mSecurity2Stub,&gEfiSecurit…

神经网络架构设计常见问题及解答

如果你是人工神经网络 (ANN) 的初学者&#xff0c;你可能会问一些问题。 比如要使用的隐藏层数量是多少&#xff1f; 每个隐藏层有多少个隐藏神经元&#xff1f; 使用隐藏层/神经元的目的是什么&#xff1f; 增加隐藏层/神经元的数量总是能带来更好的结果吗&#xff1f; 使用什…

JAVA_SE 银行存钱(控制台程序)

仓库地址&#xff1a;https://gitee.com/ThMyGitee/Bank.git CSDN的友友们&#xff0c;项目如果适合您的话&#xff0c;麻烦给个小小的Star&#xff0c;谢谢啦&#xff01; JAVA_SE 银行存钱(控制台程序) 1.流程图 2.开发环境 JDK1.8 IDEA 2019.33.界面运行 模拟转账业务&…

复习V2+V3之——02 事件处理

事件处理 事件的基本使用 1.使用v-on:xxx 或者 xxx 绑定事件&#xff0c;其中xxx是事件名 一般来说用 xxx 这种方式多一点 2.事件的回调函数需要配置在 methods 对象中&#xff0c;最终会在 vm 上面 3.methods中配置的函数&#xff0c;不要用箭头函数&#xff01;否则this…

python爬虫哪个库用的最多

目录 常用的python爬虫库有哪些 1. Requests&#xff1a; 2. BeautifulSoup&#xff1a; 3. Scrapy&#xff1a; 4. Selenium&#xff1a; 5. Scrapy-Redis&#xff1a; 哪个爬虫库用的最多 Scrapy示例代码 总结 常用的python爬虫库有哪些 Python拥有许多常用的爬虫库…

node版本控制工具nvm使用笔记

由于不同的项目所需要的node环境不同&#xff0c;所以在运行支持node 12或者node 16版本的项目时卸载安装不同版本的node非常麻烦&#xff0c;恰巧公司有一个热心的同事告诉我可以使用nvm来进行版本控制&#xff0c;我使用了之后发现确实好用&#xff0c;写一篇笔记记录一下。 …

每天晚上12点服务器关机,第二天6点自动唤醒

每天晚上12点服务器关机&#xff0c;第二天6点自动唤醒。 作用主要有4个&#xff1a; 1、防黑&#xff1a;上班时黑客很少攻击&#xff0c;容易被发现。下班了、睡了&#xff0c;是黑客攻击的主要时间段。晚上关机&#xff0c;就直接没法攻击了。 2、省电。 3、电脑开了一天…

三勾商城java多端+多店+新零售商城系统

三勾商城是开发友好的微信小程序商城&#xff0c;框架支持SAAS&#xff0c;支持发布 iOS Android 公众号 H5 各种小程序&#xff08;微信/支付宝/百度/头条/QQ/钉钉/淘宝&#xff09;等多个平台&#xff0c;不可多得的二开神器&#xff0c; 为大中小企业提供极致的移动电子…

FlutterUnit 周边 | 深入分析 iOS 手势回退问题

theme: cyanosis 1. 问题的出现 由于之前一直在 Android 机子上测试&#xff0c;没在 iOS 上跑过。最近 FlutterUnit 发布了 iOS 版本&#xff0c;收到了最多的反馈就是&#xff1a;返回滑动 失效。 起初我以为只是 WillPopScope 的锅&#xff0c;但我发现&#xff0c;很多普通…

多元回归预测 | Matlab基于遗传算法(GA)优化径向基神经网络(GA-RBF)的数据回归预测,多变量输入模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元回归预测 | Matlab基于遗传算法(GA)优化径向基神经网络(GA-RBF)的数据回归预测,多变量输入模型 评价指标包括:MAE、RMSE和R2等,代码质量极高,方便学习和替换数据。要求2018版本及以上。 部分源码 %% 清空…

java的BigDecimal操作

1.保留两位小数不进位 public static void main(String[] args) {BigDecimal bigDecimal1 new BigDecimal("1234.8888");String bigDecimal1s bigDecimal1.setScale(2, RoundingMode.DOWN).toPlainString();System.out.println(bigDecimal1s);}结果&#xff1a; …

为什么不建议项目中使用触发器

1.什么是触发器 触发器&#xff08;trigger&#xff09;是一种数据库对象&#xff0c;可以看作由事件来触发的特殊存储过程。当一个特定的事件发生时&#xff0c;会自动执行在数据库表上的某些操作&#xff0c;比如当对一个表进行操作&#xff08;insert&#xff0c;delete&am…

关系型数据库中如何进行事务管理

关系型数据库中如何进行事务管理 在关系型数据库中&#xff0c;事务管理是一项非常重要的功能。它允许数据库管理员在一个或多个数据库操作中实现原子性、一致性、隔离性和持久性&#xff08;ACID&#xff09;。 事务是一组数据库操作&#xff0c;它们必须全部执行或全部回滚…

【ACL2023】基于电商多模态概念知识图谱增强的电商场景图文模型FashionKLIP

近日&#xff0c;阿里云机器学习平台PAI与复旦大学肖仰华教授团队、阿里巴巴国际贸易事业部ICBU合作在自然语言处理顶级会议ACL2023上发表基于电商多模态概念知识图谱增强的电商场景图文模型FashionKLIP。FashionKLIP是一种电商知识增强的视觉-语言模型。该论文首先设计了从大规…

String类1

String类 单个字符可以用char类型保存&#xff0c;多个字符组成的文本就需要保存在String对象中&#xff0c;String通常被称为字符串&#xff0c;一个对象最多占用4GB的文本类容。 声明字符串 1.字符串必须包含在“”中 例&#xff1a;”234”、”你好&#xff01;” 2.声明字…