千赢娱乐手机登录_ qy8com千赢手机版_千赢网页手机版
做最好的网站

千赢娱乐手机登录

当前位置:千赢娱乐手机登录 > 千赢娱乐手机登录 > XP经验点滴,XP任务栏假死的解决方法

XP经验点滴,XP任务栏假死的解决方法

来源:http://www.modeLspro.net 作者:千赢娱乐手机登录 时间:2019-08-16 21:59

Block的引用循环问题 (ARC & non-ARC),block引用循环arc

使用Windows XP操作系统的用户,都遇到过这样的现象:操作过程中想在任务栏中切换窗口时,忽然发现点击任务栏中的图标没有任何反应了,就像系统死机一样,这就是Windows XP中常见的任务栏失去响应,又被称为“任务栏假死现象”。我们可以用下面的方法解决它。

 毫无疑问,XP是Windows有史以来最稳定的版本,但要在短时间内熟悉它可不是一件容易的事。例如,有些选项和命令的使用方式已经不同;另外,还有许多新的功能有待你去尝试、检验。本文就是为那些希望进一步熟悉Windows XP的读者所写。

 

  1. 禁用高级文字服务

  一、用Logo键快速访问

2010年WWDC发布iOS4时Apple对Objective-C进行了一次重要的升级:支持Block。说到底这东西就是闭包,其他高级语音例如Java和C 已有支持,第一次使用Block感觉满简单好用的,但是慢慢也遇到很多坑。本文聊聊ARC和non-ARC下Block使用中的引用循环问题,最近遇到了好几次这种问题,还是深入记录下。先来套题目热热身,貌似能够全部答对的人蛮少的

千赢娱乐手机登录,  Windows XP的“高级文字服务”包括了语音、手写和中文键盘输入服务,我们常用的输入法在Windows XP中也被归入高级文字服务。但是某些服务,如手写或语音功能可能与某些软件存在冲突,最明显的反应就是任务栏失去响应。例如我们清除文档记录点击“确定”或者打开多个IE快速关闭时,任务栏假死现象就很可能发生。

  今天,几乎所有的PC键盘上都带有Windows的Logo键(也称为Windows键),但很多人几乎没有注意这个画着窗口图标的键,或者简单地以为它只用来快速打开Windows开始菜单。事实并非如此。结合LOGO键和其他键,可迅速访问许多功能,例如:

Block实现原理

首先探究下Block的实现原理,由于Objective-C是C语言的超集,既然OC中的NSObject对象其实是由C语言的struct isa指针实现的,那么Block的内部实现估计也一样,以下三篇Blog对Block的实现机制做了详细研究:

  • A look inside blocks: Episode 1
  • A look inside blocks: Episode 2
  • A look inside blocks: Episode 3

虽然实现细节看着头痛,不过发现Block果然是和OC中的NSObject类似,也是用struct实现出来的东西。这个是LLVM项目compiler-rt分析的block头文Block_private.h头文件中关于Block的struct声明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct Block_descriptor {
    unsigned long int reserved;
    unsigned long int size;
    void (*copy)(void *dst, void *src);
    void (*dispose)(void *);
};

struct Block_layout {
    void *isa;
    int flags;
    int reserved;
    void (*invoke)(void *, ...);
    struct Block_descriptor *descriptor;
    /* Imported variables. */
};

我们发现Block_layout中也有一个isa指针,像极了NSobject内部实现struct中的isa指针。这里的isa可能指向三种类型之一的Block:

  • _NSConcreteGlobalBlock:全局类型Block,在编译器就已经确定,直接放在代码段__TEXT上。直接在NSLog中打印的类型为__NSGlobalBlock__。
  • _NSConcreteStackBlock:位于栈上分配的Block,即__NSStackBlock__。
  • _NSConcreteMallocBlock:位于堆上分配的Block,即__NSMallocBlock__。

为什么会有这么多种类呢?首先来看全局类型Block,看例子:

1
2
3
4
5
6
7
8
9
10
11
12
void addBlock(NSMutableArray *array) {
  [array addObject:^{
    printf("global blockn");
  }];
}

void example() {
  NSMutableArray *array = [NSMutableArray array];
  addBlock(array);
  void (^block)() = [array objectAtIndex:0];
  block();
}

为什么addBlock中添加到array中的Block属于全局Block呢?因为它不需要运行时(Runtime)任何的状态来改变行为,不需要放在堆上或者栈上,直接编译后在代码段中即可,就像个c函数一样。这种类型的Block在ARC和non-ARC情况下没有差别。

这个Block访问了作用域外的变量d,在实现上就是这个block会多一个成员变量对应这个d,在赋值block时会将方法exmpale中的d变量值复制到成员变量中,从而实现访问。

1
2
3
4
5
6
7
void example() {
  int d = 5;
  void (^block)() = ^() {
      printf("%dn", d);
  };
  block();
}

如果要修改d呢?:

1
2
3
4
5
6
7
8
9
void example() {
  int d = 5;
  void (^block)() = ^() {
      d  ;
      printf("%dn", d);
  };
  block();
  printf("%dn", d);
}

由于局部变量d和这个block的实现不在同一作用域,仅仅在调用过程中用到了值传递,所以不能直接修改,而需要加一个标识符__block int d = 5;,那么block就可以实现对这个局部变量的修改了。如果是这种block标识的变量,在Block实现中不再是简单的一个成员变量,而是对应一个新的结构体表示这个block变量。block的本质是引入了一个新的Block_byref{$var_name}{$index}结构体,被block关键字修饰的变量就被放到这个结构体中。另外,block结构体通过引入Block_byref{$var_name}{$index}指针类型的成员,得以间接访问到Block的外部变量。这样对Block外的变量访问从值传递转变为引用,从而有了修改内容的能力。

正常我们使用Block是在栈上生成的,离开了栈作用域便释放了,如果copy一个Block,那么会将这个Block copy到堆上分配,这样就不再受栈的限制,可以随意使用啦。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
typedef void (^TestBlock)();

TestBlock getBlock() {
  char e = 'E';
  void (^returnedBlock)() = ^{
    printf("%cn", e);
  };
  return returnedBlock;
}

void example() {
  TestBlock block = getBlock();
  block();
}

函数getBlock中声明并赋值的returnedBlock,一开始是在栈上分配的,属于NSStackBlock,如果是non-ARC情况下return这个NSStackBlock,那么其实已经被销毁了,在函数中example()使用时就会crash。如果是ARC情况下,getBlock返回的block会自动copy到堆上,那么block的类型就是NSMallocBlock,可以在example()中继续使用。要在Non-ARC情况下正常运行,那么就应该修改为:

1
2
3
4
5
6
7
TestBlock getBlock() {
  char e = 'E';
  void (^returnedBlock)() = ^{
    printf("%cn", e);
  };
  return [[returnedBlock copy] autorelease];
}

  其实高级文字服务中的语音、手写功能使用的人并不多,我们完全可以将其关闭。打开“控制面板”,点击“切换到经典视图”,双击“区域和语言选项”,在对话框中点击“语言”标签,再单击“详细信息”按钮,在打开的“文字服务和输入语言”对话框中点击“语言栏”,选中“关闭高级文字服务”选项后保存设置即可。

  ▲ Logo:显示“开始”菜单。

Block中的循环引用问题

扯了这么多,回到Block的循环引用问题,由于我们很多行为会导致Block的copy,而当Block被copy时,会对block中用到的对象产生强引用(ARC下)或者引用计数加一(non-ARC下)。

如果遇到这种情况:

1
2
3
4
5
6
7
8
9
@property(nonatomic, readwrite, copy) completionBlock completionBlock;

//========================================
self.completionBlock = ^ {
        if (self.success) {
            self.success(self.responseData);
        }
    }
};

对象有一个Block属性,然而这个Block属性中又引用了对象的其他成员变量,那么就会对这个变量本身产生强应用,那么变量本身和他自己的Block属性就形成了循环引用。在ARC下需要修改成这样:

1
2
3
4
5
6
7
8
9
@property(nonatomic, readwrite, copy) completionBlock completionBlock;

//========================================
__weak typeof(self) weakSelf = self;
self.completionBlock = ^ {
    if (weakSelf.success) {
        weakSelf.success(weakSelf.responseData);
    }
};

也就是生成一个对自身对象的弱引用,如果是倒霉催的项目还需要支持iOS4.3,就用__unsafe_unretained替代__weak。如果是non-ARC环境下就将__weak替换为__block即可。non-ARC情况下,__block变量的含义是在Block中引入一个新的结构体成员变量指向这个__block变量,那么__block typeof(self) weakSelf = self;就表示Block别再对self对象retain啦,这就打破了循环引用。

(ARC non-ARC),block引用循环arc 2010年WWDC发布iOS4时Apple对Objective-C进行了一次重要的升级:支持Block。说到底这东西就是闭包...

  由于中文输入法也属于高级文字服务的一部分,因此关闭服务后导致的结果就是输入法切换栏消失,我们就只能用快捷键“Ctrl Shift”来切换输入法了。

  ▲ Logo D:最小化或恢复所有的窗口。

  2. 关掉视觉特效并使用经典开始菜单

  ▲ Logo E:显示Windows资源管理器。

  有些时候的任务栏假死有可能和视觉特效有关,例如在快速关闭多个IE时产生的任务栏假死。这时我们可以在桌面“我的电脑”图标上单击鼠标右键,选择“属性”,点击“高级”标签,单击“性能”区中的“设置”按钮,在打开的“性能选项”对话框中选择“调整为最佳性能”,把所有特效关闭后保存退出。然后在“开始”按钮上点击右键,选择“属性”,选择“经典开始菜单”选项后点击“确定”保存。

  ▲ Logo F:搜索文件。

XP操作系统的用户,都遇到过这样的现象:操作过程中想在任务栏中切换窗口时,忽然发现点击任务栏中的图标没有任何反应了,...

  ▲ Logo Ctrl F:搜索计算机。

  ▲ Logo F1:帮助和支持中心。

  ▲ Logo R:“运行”对话框。

  ▲ Logo Break:系统属性对话框。

  ▲ Logo L:锁定工作站。

  ▲ Logo U:打开“工具管理器”

  Logo键从Windows 95开始就有了,不过它受人注意的时候似乎不多。但是,一旦熟悉了它,你也许再也离不开它。

  二、NetBEUI协议

  NetBEUI即NetBios Enhanced User Interface ,或NetBios增强用户接口。它是NetBIOS协议的增强版本,曾被许多操作系统采用,例如Windows for Workgroup、Win 9x系列、Windows NT、LAN Manager和LAN Server等。NETBEUI协议在许多情形下很有用,特别是如果你有一个不连接Internet的局域网。

本文由千赢娱乐手机登录发布于千赢娱乐手机登录,转载请注明出处:XP经验点滴,XP任务栏假死的解决方法

关键词: 千亿国际qy8.vip