block为什么会造成循环引用

block为什么会造成循环引用,第1张

一般来说我们总会在设置Block之后,在合适的时间回调Block,而不希望回调Block的时候Block已经被释放了,所以我们需要对Block进行copy,copy到堆中,以便后用。当一个Block被Copy的时候,如果你在Block里进行了一些调用,那么将会有一个强引用指向这些调用方法的调用者,有两个规则:如果你是通过引用来访问一个实例变量,那么将强引用至self如果你是通过值来访问一个实例变量,那么将直接强引用至这个“值”变量

小程序的template是一种模板,不能用于直接显示的代码。它正常情况下不显示,需加载使用。 <block> 并不是一个组件,它仅仅是一个包装标签元素,不会在页面中做任何渲染,只接受控制属性(如wx:if、wx:for)。

通过wxgetUserInfo获取用户的openId 和unionId,需要对接口返回的加密数据( encryptedData )进行对称解密。

/

    功能描述: <br>

    〈功能详细描述〉

   

@paramargs

@see[相关类/方法](可选)

@since[产品/模块版本](可选)

    /

publicstaticvoidmain(String[] args){

String encryptedData ="";

String sessionKey ="";

String iv ="9btKSYjvtGMGpknPpjS2Ag==";

        JSONObject jsonObject = getUserInfo(encryptedData, sessionKey, iv);

Systemoutprintln(jsonObjectgetString("unionId"));

        Systemoutprintln(jsonObjecttoJSONString());

    }

结果运行报错:

javaxcryptoBadPaddingException: pad block corrupted

at orgbouncycastlejcajceprovidersymmetricutilBaseBlockCipher$BufferedGenericBlockCipherdoFinal(Unknown Source)

at orgbouncycastlejcajceprovidersymmetricutilBaseBlockCipherengineDoFinal(Unknown Source)

at javaxcryptoCipherdoFinal(Cipherjava:2087)

at comsaicebizserviceutilAESUtilsgetUserInfo(AESUtilsjava:62)

at comsaicebizserviceutilAESUtilsmain(AESUtilsjava:86)

Exception in thread"main"javalangNullPointerException

at comsaicebizserviceutilAESUtilsmain(AESUtilsjava:87)

查询原因,有可能是我的wxlogin在wxgetUserInfo之后调的原因,细究一下

我们通过wxlogin获得用户授权码code,接下来我们用code以及appid和appSecret请求微信

>

前言:最近看了好多block相关的东西,block在项目中很常见,想必大家也都比较熟悉,可是,细细想下,又有好多迷惑?为什么会产生循环引用 为什么要用__block __block到底是干什么的如果你也有类似的困惑,那就跟我一起探究下吧。

首先探究下block的本质,他到底是个啥东东呢?

通过clang编译,我们可以看到block的内存布局,就是一个结构体,里面包含一个我么熟悉的isa指针,显然就是一个oc对象。它的底层结构就是:

通过class方法我们可以看到block有3种类型

NSGlobalBlock : 存放在数据段,没有访问auto变量(局部变量)的block(基本没啥用)

NSStackBlock:存放在栈区,访问了auto变量

NSMallocBlock:存放在堆区,NSStackBlock通过copy,从栈区拷贝到堆区

每一种block被copy后的结果

在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上。

MRC下block属性的建议写法

@property (copy, nonatomic) void (^block)(void);

ARC下block属性的建议写法

@property (strong, nonatomic) void (^block)(void);

@property (copy, nonatomic) void (^block)(void);

当block内部访问了对象类型的趋同变量时

1如果block在栈上,将不会对auto变量产生强引用

2如果block被拷贝到堆上

   21 会调用block内部的copy函数

    22 copy 函数内部会调用_block_object_assign函数

    23 _block_object_assign函数会根据auto变量的修饰符(__strong、__weak、__unsafe_unretained)作出相应的 *** 作,形成强引用还是弱引用。

3如果将block从堆上移除

    31 会调用block内部的dispose函数

    32 dispose函数会调用_Block_object_dispose函数

    33 _Block_object_dispose函数自动释放引用的auto变量

当我们想在block内部修改auto变量的时候,总是需要用__block来修饰,这是为什么呢?

31 为什么不能直接在block内部修改auto变量?

当block捕获auto变量的时候,只是获取了它的值,没有获取到它的地址,所以不能进行修改。

那么我们都知道为了解决block无法修改auto变量的问题,需要用到__block来修饰auto变量。

32 那么__block做了什么呢?

被__block 修饰过的auto变量会生成一个结构体

其中__main_block_impl_0是个新的结构体,里面包含一个age指针,这是又是一个结构体__block_byref_age_0,这个结构体的age 才是我们真正传入的值,forwarding也是一样的结构体,他是指向自己的一个指针

总结下__block的使用:

1__block可以用于解决block内部无法修改auto变量值的问题

2 __block不能修饰全局变量,静态变量

3 编译器会将__block变量包装成一个对象

41 当block在栈上,并不会对__block变量产生强引用

42 当block被拷贝到堆时

    421 会调用block内部的copy函数

    422 copy函数会调用_Block_object_assign函数   

    423 _Block_object_assign函数会对__block变量行程强引用

43 当block从堆中移除时

    431 会调用block内部的disease函数

    432 dispose函数内部会调用_Block_object_dispose函数

    433 _Block_object_dispose函数会自动释放饮用的__block变量

双方互相持有对方,都无法释放,这就是循环引用

我们经常会想到的解决方案就是用__weak 修饰,下面看看还有哪些解决方法

61 ARC

611 用__weak、__unsafe_unretained解决

612 用__block解决(必须要调用block)

62 MRC

621 用__unsafe_unretained解决

622 用__block解决

看完后,心中好多疑惑大概都解决了,那下面几道面试题来回顾下

1block的本质是什么?

答:封装了函数调用以及调用环境的oc对象

2__block 的作用是什么?有什么需要注意的?

答:作用:__block可以用于解决block内部无法修改auto变量值的问题

       注意点: __block不能修饰全局变量,静态变量;在MRC环境中,不会被强引用。

3block的属性修饰为什么是copy,使用block有哪些注意点?

答:block如果没有被copy,就不会在堆上,这样我们无法预知它的生命周期。只有将block被拷贝到堆上,我们才能管理其生命周期,想什么时候释放都行。注:ARC环境下,strong和copy没有区别,为了跟MRC环境中一样,我们喜欢用copy。

     需要注意的是,使用block不要产生循环引用。解决循环饮用的方法之前都提到过。

先前看到网上不少大神写的demo,其菜单栏主要以 A,B,C,D等字母为主,即A,B,C,D等字母为对应该项携带的 id(id不能为汉字或纯数字)。而笔者现在写的项目菜单栏为汉字,所以需要改变数据格式,进而需要改变 wxml 中的循环嵌套和获取。以下为成型后效果,希望对读者有帮助。

实现该功能的思路:通过点击左侧滑栏的某一项,获取到该元素携带的 id ,然后动态传给右侧滑栏的 scroll-into-view ,从而实现右侧滑栏对应的该元素运动置顶。

以下为完整数据

数据格式:

/ pages/listers/listerswxss /

/ pages/list-1/list-1wxss /

/ 总体主盒子 /

container {

position: relative;

width: 100%;

height: 1220rpx;

background-color: #f0f4f7;

color: #939393;

}

/ 左侧栏主盒子 /

nav_left{

/ 设置行内块级元素(没使用定位) /

display: inline-block;

width: 100%;

height: 100%;

/ 主盒子设置背景色为灰色 /

background: #fff;

text-align: center;

/ position: fixed; /

left: 0;

top: 0;

border-top: 1rpx solid #dedede;

}

/ 左侧栏list的item /

nav_left nav_left_items{

background: #fff;

/ 每个高30px /

height: 80rpx;

/ 垂直居中 /

line-height: 80rpx;

/ 再设上下padding增加高度,总高42px /

padding: 15rpx 0;

/ 只设下边线 /

border-bottom: 1px solid #dedede;

/ 文字14px /

font-size: 29rpx;

color: #101010;

font-weight:

}

/ 左侧栏list的item被选中时 /

nav_left nav_left_itemsactive{

/ 背景色变成白色/

background: #f0f4f7;

color: #ed1000;

}

/ 右侧栏主盒子 /

scroll_right{

/ 右侧盒子使用了绝对定位 /

position: fixed;

top: 0;

right: 0;

overflow: auto;

flex: 1;

/ 宽度75%,高度占满,并使用百分比布局 /

width: 75%;

height: 100%;

padding: 20rpx;

box-sizing: border-box;

background-color: #f0f4f7;

border-top: 1rpx solid #dedede;

}

mink::after{

display:block;content:'';clear:both;

}

jiul,jiul image{

width: 100%;

height: 170rpx;

}

minl{

font-size: 29rpx;

color: #777;

text-align: left;

line-height: 60rpx;

float: left;

background: #f0f4f7;

width: 100%;

/ height: 50rpx; /

}

mink{

width: 100%;

background: #fff;

height: 100%;

}

/ 右侧栏list的item /

nav_right_items{

/ 浮动向左 /

float: left;

/ 每个item设置宽度是3333% /

width: 50%;

/ height: 160rpx; /

text-align: center;

color: #4a4a4a;

background: #fff;

}

nav_right_items image{

/ 被设置宽高 /

width: 60px;

height: 50px;

margin-top: 15rpx;

}

nav_right_items text{

/ 给text设成块级元素 /

display: block;

margin-top: 5rpx;

margin-bottom: 10rpx;

font-size: 26rpx;

/ 设置文字溢出部分为 /

overflow: hidden;

white-space: nowrap;

text-overflow: ellipsis;

}

/ 自定义其他点击态样式类 /

other-navigator-hover{

background:#fff;

}

scroll_left{

width:25%;

height:100%;

background:#fff;

text-align:center;

position: fixed;

left: 0;top: 0

}

在开发微信小程序过程中,遇到一个登录的问题。就是微信小程序登录 *** 作的时候,第一次总是会失败,返回 pad block corrupted ,然后再次登录的时候就会登录成功。出现这样的错误,百度原因大多数是说 session_key 过期,到期去解密手机号数据的时候,解密出错。具体分析:

这里描述的问题是出现在第四步的步骤中,原因是第三步获取的 session_key 不正确,导致解密 *** 作错误,返回 pad block corrupted 。但是导致 session_key 不正确的原因是第二步调用 wxlogin() 方法,会刷新 session_key 。因为第一步获取的手机号加密数据是通过原来的 session_key 加密的,现在 session_key 刷新了,导致后台在第三步去获取 seesion_key 的时候,获取的是新的 seesion_key ,然后去解密的时候就报错了。

强行破处循环链 __block viewcontroller selfBlock=self; 这样就行了 在block 环里self点 变成 selfBlock点 viewcontroller 这里指的是所在页面的viewcontroller

以上就是关于block为什么会造成循环引用全部的内容,包括:block为什么会造成循环引用、微信小程序template与block的区别、微信小程序解密报错:pad block corrupted 解决方法等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/10141634.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-05
下一篇 2023-05-05

发表评论

登录后才能评论

评论列表(0条)

保存