首页 文章 精选 留言 我的

精选列表

搜索[mac],共6154篇文章
优秀的个人博客,低调大师

Mac OS X 10.15 编译和安装 Nginx

想在自己电脑里装个 Nginx 来进行各种测试,下面是详细的过程记录: 1. 下载软件 首先建个临时目录 nginx-src 并下载所需软件的源码进行配置 mkdir nginx-src cd nginx-src wget http://nginx.org/download/nginx-1.17.8.tar.gz wget https://ftp.pcre.org/pub/pcre/pcre-8.41.tar.gz wget https://www.openssl.org/source/openssl-1.1.0g.tar.gz tar zxvf *.gz cd nginx-1.17.8 ./configure --with-pcre=../pcre-8.41/ --with-http_ssl_module --with-openssl=../openssl-1.1.0g --prefix=/Users/winterlau/nginx 这里我们将 nginx 安装在 /Users/winterlau/nginx 目录下,prefix 指定的路径请使用绝对路径 2. 错误处理 如果在执行 configure 脚本时报如下错误: checking for OS + Darwin 19.2.0 x86_64 checking for C compiler ... not found ./configure: error: C compiler cc is not found 尝试执行 gcc 出如下错误 xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), ​​​​​​​missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun 执行:xcode-select --install 根据界面提示操作 3. 继续安装 ./configure --with-pcre=../pcre-8.41/ --with-http_ssl_module --with-openssl=../openssl-1.1.0g --prefix=/Users/winterlau/nginx 可看到相关信息如下: Configuration summary + using PCRE library: ../pcre-8.41/ + using OpenSSL library: ../openssl-1.1.0g + using system zlib library 开始编译安装 make make install 4. 启动 Nginx 并测试 由于默认的 nginx 运行在 80 端口上,因此需要有管理员的权限: cd ../../nginx sudo sbin/nginx 打开浏览器访问 http://localhost 收工!

优秀的个人博客,低调大师

Mac免费使用MAMP搭建本地开发环境

打开MAMP 打开偏好设置 设置端口 这里用的是Apache,选择项目路径 到这里可以先运行一下看看是否有端口占用的情况,如果80被占用改成其他的,正常就继续下面的 修改apache文件httpd.conf vi /Applications/MAMP/conf/apache/httpd.conf找到这行把#注释去掉,:wq保存退出Include /Applications/MAMP/conf/apache/extra/httpd-vhosts.conf 第一步、修改httpd-vhosts.conf文件 vi /Applications/MAMP/conf/apache/extra/httpd-vhosts.conf //配置多个项目就复制多个,主要改两个地方 //DocumentRoot 修改为项目路径 //ServerName 自定义配置本地域名 <VirtualHost *:80> ServerAdmin alf66666@163.com DocumentRoot "/Users/eric/HBuilder/userprofiles/medin/backend/web" ServerName www.m.com ErrorLog "logs/apache_error.log" CustomLog "logs/dummy-host2.example.com-access_log" common </VirtualHost> 第二步、修改系统hosts,需要权限 sudo vi /etc/hosts添加配置的本地域名,就是上面的ServerName 127.0.0.1 www.m.com 第三步、重启MAMP 如果配置多个项目,只需要重复上面三步就可以了 以上步骤做完,可以正常运行了或许有其他报错情况 The requested URL index.php was not found on this server. 如果项目是Nginx运行的,选择Apache也是可以的,在项目目录(第一步配置的DocumentRoot)下添加.htaccess文件 // vi /Applications/MAMP/conf/apache/httpd.conf //修改apache文件httpd.conf //AllowOverride None 改为 AllowOverride All <Directory "/Applications/MAMP/bin/phpPgAdmin"> Options All AllowOverride All Order allow,deny Allow from all </Directory> 如果有端口6379 Redis等报错情况,可能是后端根据本地域名必须包含哪些英文字母来配置不同数据库等等,所以要和后端约定好本地域名规则,按照规则配置域名

优秀的个人博客,低调大师

compile php with openssl on mac osx error 填坑

从源码手动编译 PHP 时出现如下错误: Default 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Undefined symbols for architecture x86_64: "_PKCS5_PBKDF2_HMAC", referenced from: _zif_openssl_pbkdf2 in openssl.o "_TLSv1_1_client_method", referenced from: _php_openssl_setup_crypto in xp_ssl.o "_TLSv1_1_server_method", referenced from: _php_openssl_setup_crypto in xp_ssl.o "_TLSv1_2_client_method", referenced from: _php_openssl_setup_crypto in xp_ssl.o "_TLSv1_2_server_method", referenced from: _php_openssl_setup_crypto in xp_ssl.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) make: *** [libs/libphp5.bundle] Error 1 解决办法 MakeFile 里面找到类似下面这一行: Default 1 EXTRA_LIBS = -lresolv -lmcrypt -lltdl -liconv-lm -lxml2 -lcurl -lssl -lcrypto 删除所有的 -lssl 和-lcrypto 然后添加libssl.dylib 和 libcrypto.dylib 的路径(如果你安装了 brew,那么则是 /usr/local/opt/openssl/lib/),重新运行 make 命令,done。 附上我修改后的 MakeFile EXTRA_LIBS 那一行: Default 1 EXTRA_LIBS = -lz -lresolv -lmcrypt -lltdl -lstdc++ -liconv -liconv -lpng -lz -lcurl -lz -lm -lxml2 -lz -licucore -lm -lcurl -lxml2 -lz -licucore -lm -licui18n -licuuc -licudata -licuio -lxml2 -lz -licucore -lm -lxml2 -lz -licucore -lm -lxml2 -lz -licucore -lm -lxml2 -lz -licucore -lm /usr/local/opt/openssl/lib/libssl.dylib /usr/local/opt/openssl/lib/libcrypto.dylib The Makefile has a line withEXTRA_LIBS, something like: EXTRA_LIBS = -lresolv -lmcrypt -lltdl -liconv-lm -lxml2 -lcurl -lssl -lcrypto Remove all occurrences of-lssland-lcryptoand add the full path tolibssl.dylibandlibcrypto.dylib(brew links openssl to /usr/local/opt/openssl/lib/) EXTRA_LIBS = -lresolv -lmcrypt /usr/local/opt/openssl/lib/libssl.dylib /usr/local/opt/openssl/lib/libcrypto.dylib -lltdl -liconv-lm -lxml2 -lcurl 谋胆并重

优秀的个人博客,低调大师

mac下如何使用appledoc生成文档

前言 近期手头项目需要出一下文档,方便使用者查阅。调研了目前比较流行的三款文档生成工具HeaderDoc,Doxygen,appledoc。 Doxygen Doxygen是C++源码生成文档的标准工具,同时也支持很多其它语言如:C,Objective-C,C#,PHP,Java,Python等等。然而,它生成的文档风格和官方文档的风格差了十万八千里,并且配置复杂。 HeaderDoc HeaderDoc是苹果官方的文档生成工具。Xcode9以前在安装完Xcode后就可以使用,Xcode9是个重构版本,并没有继承这个。该工具对注释生成规则比较特别,只生成以/*! */ 的格式的注释。生成文档是分散的,并没有一个汇总文件。 appledoc appledoc只专注Objective-C源代码,并且能生成和苹果官方相同风格的文档。同时支持生成html和直接编译成docset安装进Xcode。代码开源在github上,作者会及时跟开发者沟通。 安装 官方推荐做法是克隆GitHub项目并从Xcode编译该工具。由于克隆GitHub项目将创建与主存储库的链接,它也极大地简化了未来的升级。要进行安装,请在终端中输入以下内容: git clone git://github.com/tomaz/appledoc.git cd ./appledoc sudo sh install-appledoc.sh(如果需要安装模板文件,需添加'-t default') 还可以使用Homebrew进行安装 brew install appledoc 注意:Homebrew默认不会安装模板 安装完成,验证一下是否成功,如果显示版本号则证明安装成功。 appledoc --version 使用 为了演示使用,我创建了测试工程,代码如下完成了代码的书写,切换到命令行,cd到源码所在的目录,执行以下命令 appledoc -p project_name -v project_version -c company_name --company-id company_id -o ./doc . 如果不想生成docset,可以添加—no-create-docset。想了解更多的话,命令行下可以通过appledoc —help查看。 生成的html:很像苹果官方文档的风格吧~ 部署 生成好的html如何部署到服务器?我的项目是在github,可以通过github pages来实现。简单说就是在github账号下新建一个username.github.io的仓库,然后将生成的doc目录下html目录中的全部内容上传到github该仓库下,然后就可以通过在浏览器中输入 http://username.github.io 来访问生成的文档了

优秀的个人博客,低调大师

Mac查看文件内容常用的命令小结

前言 最近苹果的热更新和私有库问题检查的更严了,如果应用被拒,苹果在拒绝信中会说到使用strings/otool/nm命令进行自查,所以总结了一些命令,方便查找和定位文件内容相关信息。 1、grep 作用:判断是否包含字符串 使用示例: grep -r "xxx” path 检查是否包含(weixin)字符串: grep -r "xxx” path.png matches 表示包含。 2、strings 作用:find the printable strings in a object, or other binary, file 使用示例: strings a.out | grep hello //检查 a.out 文件中含有 hello 字符串的字节序列 检查二进制是否含有关键词的库(比如检查私有库): strings a.out | grep hello.png 更多使用说明 man strings 3、otool 作用: object file displaying tool. (针对目标文件的展示工具,用来发现应用中使用到了哪些系统库,调用了其中哪些方法,使用了库中哪些对象及属性) 使用示例:otool -L path //查看可执行程序都链接了那些库 otool -L path | grep "xxx" //筛选是否链接了xxx库 otool -D path //查看支持的架构 otool -ov path //output the Objective-C class structures and their defined methods.(输出Object-C类结构以及定义的方法) 查看该应用是否砸壳:otool -l path | grep crypt //cryptid 0(砸壳) 1(未砸壳) otool -l path | grep crypt.png 更多用法 man otool 4、nm 作用:display name list (symbol table). (显示符号表) 使用示例:nm path //得到Mach-O中的程序符号表 nm -nm path//目标文件的所有符号 nm -nm path.png 符号表中标示为 undefined,意思是目标文件引用了类_XXX(XXX库),不过这并没有实现它。 更多用法 man nm 5、file 作用:determine file type. (判断文件类型) 使用示例:file path 判断.a/framework是静态库还是动态库: 静态库: file path - static Lib.png 动态库: file path - dynamically Lib.png 6、lipo 作用:create or operate on universal files(创建或处理通用文件的工具) 使用示例:lipo -info 'file path' // 判断静态库所支持的平台 - i386 armv7 armv7s x86_64 arm64 lipo -remove i386 origin_xxx.a -output op_xxx.a // 删除静态库包括的i386平台 lipo -thin i386 origin_xxx.a -output op_xxx.a // 拆分静态库,只保留i386 CPU架构 lipo -create device_xxx.a simulator_xxx.a -output universal_xxx.a //对真机或者模拟器分别打出 .a 文件合并 参考阅读 "nm tool" Xcode manual page iOS-private-api-scanner/iOS私有API扫描工作总结· mrmign/iOS-private-api-scanner iOS-private-api-checker苹果iOS私有API检查工具 iOS开发-如何判断framework是动态库或静态库以及framework静态库转.a静态库 注:本文首发于 iHTCboy's blog,如若转载,请注明来源。

优秀的个人博客,低调大师

MAC使用Nginx搭建RTMP服务器

1、先安装homeView 安装命令 ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 移除命令 ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/uninstall)" 2、安装Nginx服务器 增加对 nginx 的扩展;也就是从github上下载,home-brew对ngixnx的扩展 brew tap homebrew/nginx 3、安装Nginx服务器和rtmp模块,安装过程有点久。稍等。 brew install nginx-full --with-rtmp-module 4、查看nginx的信息 brew info nginx-full nginx的安装位置 /usr/local/Cellar/nginx-full/1.10.1/bin/nginx nginx配置文件所在位置 /usr/local/etc/nginx/nginx.conf nginx服务器根目录所在位置 /usr/local/var/www 使用命令开启nginx: nginx 在浏览器地址栏输入:http://localhost:8080 (直接点击) 图1.jpg 5、配置rtmp open /usr/local/etc/nginx 打开niginx的文件夹,找到nginx.conf文件,用xcode打开。添加下面配置 #在http节点下面(也就是文件的尾部)加上rtmp配置: rtmp {#协议名称 server {#说明内部中是服务器相关配置 listen 12345;#监听的端口号, rtmp协议的默认端口号是1935 application zbcs {#访问的应用路径是 zbcs live on; #开启实时 record off;#不记录数据 } } } 图2.jpg 6、 保存文件后,重新加载nginx的配置文件。 重要操作!一定要重启nginx nginx -s reload 7、 安装ffmepg工具 brew install ffmpeg 8、推流 ffmpeg -re -i /Users/mazaiting/Downloads/台球.mp4 -vcodec copy -f flv rtmp://localhost:12345/zbcs/room 其中abcs是配置文件中的应用名,12345是配置文件中的端口,room可以随便写,"/Users/mazaiting/Downloads/台球.mp4"是推流的视频。 9、观看 使用软件VLC MediaPlayer打开网络串流,Open Media...->Network,输入rtmp://localhost:12345/zbcs/room,点击Open进行观看。 图3.jpg

优秀的个人博客,低调大师

Mac上phantomjs装了不能用的解决

下了,装了。然后整这句命令: 1 phantomjs --version 直接报错。。 查了半天的官方文档,居然连个毛线都么找到。终于。。。墨迹到了一个方法,就抱着试一试的心态在terminal里输入了这个命令: 1 export PATH= "$PATH:/Users/username/phantomjs-1.9.2-macosx/bin/" X!再试那个命令居然就管用了。里面的路径自己根据自己的情况修改,这个就不用多说了吧。 欢迎加群互相学习,共同进步。QQ群:iOS: 58099570 | Android: 572064792 | Nodejs:329118122 做人要厚道,转载请注明出处! 本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sunshine-anycall/p/3994011.html ,如需转载请自行联系原作者

优秀的个人博客,低调大师

iPhone/Mac Objective-C内存管理原理

初学objectice-C的朋友都有一个困惑,总觉得对objective-C的内存管理机制琢磨不透,程序经常内存泄漏或莫名其妙的崩溃。我在这里总结了自己对objective-C内存管理机制的研究成果和经验,写了这么一个由浅入深的教程。希望对大家有所帮助,也欢迎大家一起探讨。 此文涉及的内存管理是针对于继承于NSObject的Class。 一 基本原理 Objective-C的内存管理机制与.Net/Java那种全自动的垃圾回收机制是不同的,它本质上还是C语言中的手动管理方式,只不过稍微加了一些自动方法。 1 Objective-C的对象生成于堆之上,生成之后,需要一个指针来指向它。 ClassA *obj1 = [[ClassA alloc] init]; 2 Objective-C的对象在使用完成之后不会自动销毁,需要执行dealloc来释放空间(销毁),否则内存泄露。 [obj1 dealloc]; 这带来了一个问题。下面代码中obj2是否需要调用dealloc? ClassA *obj1 = [[ClassA alloc] init];ClassA *obj2 = obj1;[obj1 hello]; //输出hello[obj1 dealloc];[obj2 hello]; //能够执行这一行和下一行吗?[obj2 dealloc]; 不能,因为obj1和obj2只是指针,它们指向同一个对象,[obj1 dealloc]已经销毁这个对象了,不能再调用[obj2 hello]和[obj2 dealloc]。obj2实际上是个无效指针。 如何避免无效指针?请看下一条。 3 Objective-C采用了引用计数(ref count或者retain count)。对象的内部保存一个数字,表示被引用的次数。例如,某个对象被两个指针所指向(引用)那么它的retain count为2。需要销毁对象的时候,不直接调用dealloc,而是调用release。release会让retain count减1,只有retain count等于0,系统才会调用dealloc真正销毁这个对象。 ClassA *obj1 = [[ClassA alloc] init]; //对象生成时,retain count = 1[obj1 release]; //release使retain count减1,retain count = 0,dealloc自动被调用,对象被销毁 我们回头看看刚刚那个无效指针的问题,把dealloc改成release解决了吗? ClassA *obj1 = [[ClassA alloc] init]; //retain count = 1 ClassA *obj2 = obj1; //retain count = 1 [obj1 hello]; //输出hello [obj1 release]; //retain count = 0,对象被销毁 [obj2 hello]; [obj2 release]; [obj1 release]之后,obj2依然是个无效指针。问题依然没有解决。解决方法见下一条。 4 Objective-C指针赋值时,retain count不会自动增加,需要手动retain。 ClassA *obj1 = [[ClassA alloc] init]; //retain count = 1 ClassA *obj2 = obj1; //retain count = 1 [obj2 retain]; //retain count = 2 [obj1 hello]; //输出hello [obj1 release]; //retain count = 2 – 1 = 1 [obj2 hello]; //输出hello [obj2 release]; //retain count = 0,对象被销毁 问题解决!注意,如果没有调用[obj2 release],这个对象的retain count始终为1,不会被销毁,内存泄露。(1-4可以参考附件中的示例程序memman-no-pool.m) 这样的确不会内存泄露,但似乎有点麻烦,有没有简单点的方法?见下一条。 5 Objective-C中引入了autorelease pool(自动释放对象池),在遵守一些规则的情况下,可以自动释放对象。(autorelease pool依然不是.Net/Java那种全自动的垃圾回收机制) 5.1 新生成的对象,只要调用autorelease就行了,无需再调用release! ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1 但无需调用release 5.2 对于存在指针赋值的情况,代码与前面类似。 ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1 ClassA *obj2 = obj1; //retain count = 1 [obj2 retain]; //retain count = 2 [obj1 hello]; //输出hello //对于obj1,无需调用(实际上不能调用)release [obj2 hello]; //输出hello [obj2 release]; //retain count = 2-1 = 1 细心的读者肯定能发现这个对象没有被销毁,何时销毁呢?谁去销毁它?(可以参考附件中的示例程序memman-with-pool.m)请看下一条。 6 autorelease pool原理剖析。(其实很简单的,一定要坚持看下去,否则还是不能理解Objective-C的内存管理机制。) 6.1 autorelease pool不是天生的,需要手动创立。只不过在新建一个iphone项目时,xcode会自动帮你写好。autorelease pool的真名是NSAutoreleasePool。 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 6.2 NSAutoreleasePool内部包含一个数组(NSMutableArray),用来保存声明为autorelease的所有对象。如果一个对象声明为autorelease,系统所做的工作就是把这个对象加入到这个数组中去。 ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1,把此对象加入autorelease pool中 6.3 NSAutoreleasePool自身在销毁的时候,会遍历一遍这个数组,release数组中的每个成员。如果此时数组中成员的retain count为1,那么release之后,retain count为0,对象正式被销毁。如果此时数组中成员的retain count大于1,那么release之后,retain count大于0,此对象依然没有被销毁,内存泄露。 6.4 默认只有一个autorelease pool,通常类似于下面这个例子。 int main (int argc, const char *argv[]) { NSAutoreleasePool *pool; pool = [[NSAutoreleasePool alloc] init]; // do something [pool release]; return (0); } // main 所有标记为autorelease的对象都只有在这个pool销毁时才被销毁。如果你有大量的对象标记为autorelease,这显然不能很好的利用内存,在iphone这种内存受限的程序中是很容易造成内存不足的。例如: int main (int argc, const char *argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; int i, j; for (i = 0; i < 100; i++ ) { for (j = 0; j < 100000; j++ ) [NSString stringWithFormat:@"1234567890"];//产生的对象是autorelease的。 } [pool release]; return (0); } // main (可以参考附件中的示例程序memman-many-objs-one-pool.m,运行时通过监控工具可以发现使用的内存在急剧增加,直到pool销毁时才被释放)你需要考虑下一条。 7 Objective-C程序中可以嵌套创建多个autorelease pool。在需要大量创建局部变量的时候,可以创建内嵌的autorelease pool来及时释放内存。(感谢网友hhyytt和neogui的提醒,某些情况下,系统会自动创建autorelease pool, 请参见第四章) int main (int argc, const char *argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; int i, j; for (i = 0; i < 100; i++ ) { NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init]; for (j = 0; j < 100000; j++ ) [NSString stringWithFormat:@"1234567890"];//产生的对象是autorelease的。 [loopPool release]; } [pool release]; return (0); } // main (可以参考附件中的示例程序memman-many-objs-many-pools.m,占用内存的变化极小) 二 口诀与范式 1 口诀。 1.1 谁创建,谁释放(类似于“谁污染,谁治理”)。如果你通过alloc、new或copy来创建一个对象,那么你必须调用release或autorelease。换句话说,不是你创建的,就不用你去释放。 例如,你在一个函数中alloc生成了一个对象,且这个对象只在这个函数中被使用,那么你必须在这个函数中调用release或autorelease。如果你在一个class的某个方法中alloc一个成员对象,且没有调用autorelease,那么你需要在这个类的dealloc方法中调用release;如果调用了autorelease,那么在dealloc方法中什么都不需要做。 1.2 除了alloc、new或copy之外的方法创建的对象都被声明了autorelease。 1.3 谁retain,谁release。只要你调用了retain,无论这个对象是如何生成的,你都要调用release。有时候你的代码中明明没有retain,可是系统会在默认实现中加入retain。不知道为什么苹果公司的文档没有强调这个非常重要的一点,请参考范式2.7和第三章。 2 范式。 范式就是模板,就是依葫芦画瓢。由于不同人有不同的理解和习惯,我总结的范式不一定适合所有人,但我能保证照着这样做不会出问题。 2.1 创建一个对象。 ClassA *obj1 = [[ClassA alloc] init]; 2.2 创建一个autorelease的对象。 ClassA *obj1 = [[[ClassA alloc] init] autorelease]; 2.3 Release一个对象后,立即把指针清空。(顺便说一句,release一个空指针是合法的,但不会发生任何事情) [obj1 release];obj1 = nil; 2.4 指针赋值给另一个指针。 ClassA *obj2 = obj1;[obj2 retain];//do something[obj2 release];obj2 = nil; 2.5 在一个函数中创建并返回对象,需要把这个对象设置为autorelease ClassA *Func1(){ ClassA *obj = [[[ClassA alloc]init]autorelease]; return obj;} 2.6 在子类的dealloc方法中调用基类的dealloc方法 -(void) dealloc{ … [super dealloc];} 2.7 在一个class中创建和使用property。 2.7.1 声明一个成员变量。 ClassB *objB; 2.7.2 声明property,加上retain参数。 @property (retain) ClassB* objB; 2.7.3 定义property。(property的默认实现请看第三章) @synthesize objB; 2.7.4 除了dealloc方法以外,始终用.操作符的方式来调用property。 self.objB 或者objA.objB 2.7.5 在dealloc方法中release这个成员变量。 [objB release]; 示例代码如下(详细代码请参考附件中的memman-property.m,你需要特别留意对象是在何时被销毁的。): @interface ClassA : NSObject { ClassB* objB; } @property (retain) ClassB* objB; @end @implementation ClassA @synthesize objB; -(void) dealloc { [objB release]; [super dealloc]; } @end 2.7.6 给这个property赋值时,有手动release和autorelease两种方式。 void funcNoAutorelease() { ClassB *objB1 = [[ClassB alloc]init]; ClassA *objA = [[ClassA alloc]init]; objA.objB = objB1; [objB1 release]; [objA release]; } void funcAutorelease() { ClassB *objB1 = [[[ClassB alloc]init] autorelease]; ClassA *objA = [[[ClassA alloc]init] autorelease]; objA.objB = objB1; } 三 @property (retain)和@synthesize的默认实现 在这里解释一下@property (retain) ClassB* objB;和@synthesize objB;背后到底发生了什么(retain property的默认实现)。property实际上是getter和setter,针对有retain参数的property,背后的实现如下(请参考附件中的memman-getter-setter.m,你会发现,结果和memman-property.m一样): @interface ClassA : NSObject { ClassB *objB; } -(ClassB *) getObjB; -(void) setObjB:(ClassB *) value; @end @implementation ClassA -(ClassB*) getObjB { return objB; } -(void) setObjB:(ClassB*) value { if (objB != value) { [objB release]; objB = [value retain]; } } 在setObjB中,如果新设定的值和原值不同的话,必须要把原值对象release一次,这样才能保证retain count是正确的。 由于我们在class内部retain了一次(虽然是默认实现的),所以我们要在dealloc方法中release这个成员变量。 -(void) dealloc{ [objB release]; [super dealloc];} 四 系统自动创建新的autorelease pool 在生成新的Run Loop的时候,系统会自动创建新的autorelease pool(非常感谢网友hhyytt和neogui的提醒)。注意,此处不同于xcode在新建项目时自动生成的代码中加入的autorelease pool,xcode生成的代码可以被删除,但系统自动创建的新的autorelease pool是无法删除的(对于无Garbage Collection的环境来说)。Objective-C没有给出实现代码,官方文档也没有说明,但我们可以通过小程序来证明。 在这个小程序中,我们先生成了一个autorelease pool,然后生成一个autorelease的ClassA的实例,再在一个新的run loop中生成一个autorelease的ClassB的对象(注意,我们并没有手动在新run loop中生成autorelease pool)。精简的示例代码如下,详细代码请见附件中的memman-run-loop-with-pool.m。 int main(int argc, char**argv) { NSLog(@"create an autorelasePool\n"); NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSLog(@"create an instance of ClassA and autorelease\n"); ClassA *obj1 = [[[ClassA alloc] init] autorelease]; NSDate *now = [[NSDate alloc] init]; NSTimer *timer = [[NSTimer alloc] initWithFireDate:now interval:0.0 target:obj1 selector:@selector(createClassB) userInfo:nil repeats:NO]; NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; [runLoop addTimer:timer forMode:NSDefaultRunLoopMode]; [timer release]; [now release]; [runLoop run]; //在新loop中调用一函数,生成ClassB的autorelease实例 NSLog(@"releasing autorelasePool\n"); [pool release]; NSLog(@"autorelasePool is released\n"); return 0; } 输出如下: create an autorelasePool create an instance of ClassA and autorelease create an instance of ClassB and autorelease ClassB destroyed releasing autorelasePool ClassA destroyed autorelasePool is released 注意在我们销毁autorelease pool之前,ClassB的autorelease实例就已经被销毁了。 有人可能会说,这并不能说明新的run loop自动生成了一个新的autorelease pool,说不定还只是用了老的autorelease pool,只不过后来drain了一次而已。我们可以在main函数中不生成autorelease pool。精简的示例代码如下,详细代码请见附件中的memman-run-loop-without-pool.m。 int main(int argc, char**argv) { NSLog(@"No autorelasePool created\n"); NSLog(@"create an instance of ClassA\n"); ClassA *obj1 = [[ClassA alloc] init]; NSDate *now = [[NSDate alloc] init]; NSTimer *timer = [[NSTimer alloc] initWithFireDate:now interval:0.0 target:obj1 selector:@selector(createClassB) userInfo:nil repeats:NO]; NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; [runLoop addTimer:timer forMode:NSDefaultRunLoopMode]; [timer release]; [now release]; [runLoop run]; //在新loop中调用一函数,生成ClassB的autorelease实例 NSLog(@"Manually release the instance of ClassA\n"); [obj1 release]; return 0; } 输出如下: No autorelasePool created create an instance of ClassA create an instance of ClassB and autorelease ClassB destroyed Manually release the instance of ClassA ClassA destroyed 我们可以看出来,我们并没有创建任何autorelease pool,可是ClassB的实例依然被自动销毁了,这说明新的run loop自动创建了一个autorelease pool,这个pool在新的run loop结束的时候会销毁自己(并自动release所包含的对象)。 补充说明 在研究retain count的时候,我不建议用NSString。因为在下面的语句中, NSString *str1 = @”constant string”; str1的retain count是个很大的数字。Objective-C对常量字符串做了特殊处理。 当然,如果你这样创建NSString,得到的retain count依然为1 NSString *str2 = [NSString stringWithFormat:@”123”]; 本文转自 wws5201985 51CTO博客,原文链接:http://blog.51cto.com/wws5201985/742539,如需转载请自行联系原作者

优秀的个人博客,低调大师

从无到有搭建Macaca环境(for Mac)

官方环境配置教程:https://macacajs.com/environment-setup Macaca官方提供了环境配置指南(地址如上),但官方文档中多处是针对有相应开发经验的同学介绍,对于新手来讲入门成本较高,且我们在实践中也常会遇到一些问题,导致环境配置受阻,本文基于笔者配置中的经验,总结了配置过程中的详细步骤,旨在提供一个详尽的Macaca环境配置指南,帮助新手们从无到有的搭建一套Macaca开发环境,作为官方指南的补充和细化,欢迎拍砖。 基础环境准备 安装Homebrew 参考官网 简易安装步骤(最新可参考官网) $ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 安装Node和np

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册