首页 文章 精选 留言 我的

精选列表

搜索[天玑9500],共10000篇文章
优秀的个人博客,低调大师

仅一天搭建直播系统平台!

随着手机直播的火热,手机直播开发便获得越来越多的人讨论,甚至有人说手机直播开发只需要三个步骤!这对很多人来讲是很不可思议的。小编认为这说的对也不对,接下来小编具体分析一下。 首先,手机直播开发分三步确实可以搭建起来: 第一步:分解手机直播系统开发功能,了解你所需要的直播功能第二步:寻找合适的云服务SDK进行嵌入,在APICloud的聚合API中可以轻易找到以上的功能模块,挑选合适的模块封装到自己的App中第三步:1. App框架搭建,在APICloud Studio中直接创建应用框架,有三个常用页面框架备选;2.积木式拼装,将所有你挑选好的模块,用Java编写页面及模块调用,运用HTML5+CSS3搭建应用的界面UI,完成App编码全过程;3.真机调试,通过模拟器和真机调试功能进行App优化,一键点击即可在iOS和Android手机中进行App优化;4.云编译,在APICloud网上传App的icon、启动页和证书,一键“云编译”即可同时生成iOS和Android的原生安装包;5.云修复,使用云修复快速迭代,随时发布新版本、新功能,无需提交新的安装包。这就是三个步骤,但是手机直播开发是一个浩大的工程还需不断探索。

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

第23天,Django之中间件

目录 一、中间件简介 Django官方文档描述 二、激活中间件 三、中间件包含的钩子方法和应用的顺序 1. 钩子方法的调用 1.1 process_request 1.2 process_view 1.3 process_template_response 1.4 process_response 1.5 process_exception 四、编写自己的中间件 1. 正常流程 2. process_request返回HttpResponse 3. 加入process_view()方法 3.1 将上述中间件代码中M3.process_request()返回一个HttpResponse(其余代码不变): 3.2 M2.process_view()返回HttpResponse,M3.process_request()返回None,其余代码不变: 4. 加入process_exception()方法 4.1 将上述中间件代码中的M2.process_response()返回HttpResponse 五、中间件应用场景 1、做IP限制 2、URL访问过滤 3、缓存(还记得CDN吗?) 一、中间件简介 在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。 Django官方文档描述 中间件是一个钩子框架,它们可以介入Django 的请求和响应处理过程。它是一个轻量级、底层的“插件”系统,用于在全局修改Django 的输入或输出。 每个中间件组件负责完成某个特定的功能。例如,Django 包含的一个中间件组件AuthenticationMiddleware ,它使用会话将用户和请求关联起来。 这篇文档讲解中间件如何工作、如何激活中间件以及如何编写你自己的中间件。Django集成了一些内置的中间件可以直接开箱即用。它们被归档在 .内置中间件参考 二、激活中间件 要激活一个中间件组件,需要把它添加到Django项目的配置文件settings.py中的MIDDLEWARE列表中。 在MIDDLEWARE中,每一个中间件组件用字符串的方式描述:一个完整的Python全路径加上中间件的类名称。例如,使用django-admin startproject创建项目的时候生成的默认值: MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.locale.LocaleMiddleware', # admin界面默认是显示英语,如果要显示中文,就添加这一行中间件 ] Django的程序中,中间件不是必需的---只要你喜欢,MIDDLEWARE列表可以为空,但是强烈推荐你至少使用CommonMiddleware这个中间件。 MIDDLEWARE中的顺序非常重要,因为一个中间件可能依赖于另外一个。因为一个中间件可能依赖于另外一个。例如,AuthenticationMiddleware在会话中储存已认证的用户。所以它必须在SessionMiddleware之后运行。一些关于Django中间件类的顺序的常见提示,请见中间件排序。 三、中间件包含的钩子方法和应用的顺序 在请求阶段中,调用视图之前,Django会按照MIDDLEWARE中定义的顺序自顶向下应用中间件。会用到两个钩子: process_request(request) process_view(request, view_func, view_args, view_kwargs) 在响应阶段中,调用视图之后,中间件会按照相反的顺序应用,自底向上。会用到三个钩子: process_exception(request, exception process_template_response(request, response) process_response(request, response) 中间件钩子方法应用顺序 上面5种钩子方法,你可以在自己写的中间件类中定义其中一种或多种。 1. 钩子方法的调用 1.1 process_request process_request(request) request是一个HttpRequest 对象。 Django在执行视图函数前,先从上往下调用每个中间件的process_request()方法。它应该返回一个None或一个HttpResponse对象。如果返回None(不写返回值相当于返回None),Django会继续调用下一个中间件的process_request()方法,当所有中间件的process_request()方法全部调用完毕且没有返回HttpResponse对象时,再从第一个中间件开始依次调用每个中间件的process_view()方法,最后执行对应的视图函数。如果它返回一个HttpResponse对象,Django就不用再去调用其它中间件的process_request()、process_view()或process_exception()和视图函数了,它将对HttpResponse 运用响应阶段的中间件,并返回结果。 1.2 process_view process_view(request, view_func, view_args, view_kwargs) request是一个HttpRequest对象。view_func是个视图函数, view_args是一个会被传递到视图的位置参数列表,而view_kwargs 是一个会被传递到视图的关键字参数字典。 view_args和 view_kwargs 都不包括第一个视图参数(request)。 process_view()会在Django 调用视图之前被调用。 它将返回None 或一个HttpResponse 对象。如果返回None,Django 将会继续执行其它的process_view() 中间件,然后调用对应的视图。如果返回一个HttpResponse对象,Django 就不用再去调用其它的view 或exception 中间件,或对应的视图;它将对HttpResponse 运用响应阶段的中间件,并返回结果。 注意:在中间件内部,从process_request 或process_view 中访问request.POST 或request.REQUEST 将阻碍该中间件之后的所有视图无法修改请求的上传处理程序,一般情况下要避免这样使用。 类CsrfViewMiddleware可以被认为是个例外,因为它提供csrf_exempt() 和csrf_protect()两个装饰器,允许视图显式控制在哪个点需要开启CSRF验证。 1.3 process_template_response 这个钩子实际中使用的较少 process_template_response(request, response) request是一个HttpRequest对象。response是一个TemplateResponse对象(或等价的对象),由Django视图或者中间件返回。 如果响应的实例有render()方法,process_template_response()在视图刚好执行完毕之后被调用,这表明了它是一个TemplateResponse对象(或等价的对象)。 这个方法必须返回一个实现了render方法的响应对象。它可以修改给定的response对象,通过修改 response.template_name和response.context_data或者它可以创建一个全新的 TemplateResponse或等价的对象。 你不需要显式渲染响应 —— 一旦所有的模板响应中间件被调用,响应会自动被渲染。 在一个响应的处理期间,中间件以相反的顺序运行,这包括process_template_response()。 1.4 process_response process_response(request, response) process_response()在所有响应返回浏览器之前被调用。 request是一个HttpRequest对象。response是Django视图或者中间件返回的HttpResponse或者StreamingHttpResponse对象。 这个方法必须返回HttpResponse或者StreamingHttpResponse对象。它可以改变已有的response,或者创建并返回新的HttpResponse或StreamingHttpResponse对象。 不像 process_request()和process_view()方法,即使同一个中间件类中的process_request()和process_view()方法会因为前面的一个中间件返回HttpResponse而被跳过,process_response()方法总是会被调用。特别是,这意味着你的process_response()方法不能依赖于process_request()方法中的设置。 注意:最后,记住在响应阶段中,中间件以相反的顺序被应用,自底向上。意思是定义在MIDDLEWARE最底下的类的process_response()会最先被运行。 1.5 process_exception process_exception(request, exception) 当一个视图抛出异常时,Django会调用process_exception()来处理。 request是一个HttpRequest对象。exception是一个被视图中的方法抛出来的 Exception对象。 process_exception()应该返回一个None 或者一个HttpResponse对象。如果它返回一个HttpResponse对象,模型响应和响应中间件会被应用,响应结果会返回给浏览器。否则, 默认的异常处理机制将会被触发。 再次提醒,在处理响应期间,中间件的执行顺序是倒序执行的,这包括process_exception。如果一个异常处理的中间件返回了一个响应,那这个中间件上面的中间件都将不会被调用。 四、编写自己的中间件 Django版本 >> django-admin version 1.11.7 自己写的中间件(类)必须继承MiddlewareMixin 1. 正常流程 只有process_request和process_response时 from django.shortcuts import HttpResponse from django.utils.deprecation import MiddlewareMixin class M1(MiddlewareMixin): def process_request(self,request): print('中间件: M1.process_request') def process_response(self,request,response): print('中间件:M1.process_response') return response class M2(MiddlewareMixin): def process_request(self,request): print('中间件:M2.process_request') def process_response(self,request,response): print('中间件:M2.process_response') return response class M3(MiddlewareMixin): def process_request(self,request): print('中间件:M3.process_request') def process_response(self,request,response): print('中间件:M3.process_response') return response 在settings.py中注册自己编写的中间件: MIDDLEWARE = [ ... 'middleware.testMiddleWare.M1', 'middleware.testMiddleWare.M2', 'middleware.testMiddleWare.M3', ... ] 写一个简单的视图test def test(request): print('views.test') return HttpResponse('ok') urls.py中添加一条url urlpatterns = [ ... url(r'test/', views.test), ] 访问http://127.0.0.1:8000/test/后,后端打印结果如下: 中间件: M1.process_request 中间件:M2.process_request 中间件:M3.process_request 视图函数:views.test 中间件:M3.process_response 中间件:M2.process_response 中间件:M1.process_response 从输出结果,可以得出执行流程如下图: 执行流程1 2. process_request返回HttpResponse 将上述中间件代码中的M2.process_request()返回HttpResponse(其余代码不变): class M2(MiddlewareMixin): def process_request(self,request): print('中间件:M2.process_request') return HttpResponse('前端显示:中间件:M2.process_request') def process_response(self,request,response): print('中间件:M2.process_response') return response 前端显示结果: 前端显示:中间件:M2.process_request 后端输入结果: 中间件: M1.process_request 中间件:M2.process_request 中间件:M2.process_response 中间件:M1.process_response 从输出结果,可以得出执行流程如下图: 执行流程2 M2.process_request()返回HttpResponse后,不再执行后面中间件的process_request()方法和视图函数,直接依次往上(倒序)执行M2和M1的process_response()方法。 3. 加入process_view()方法 from django.shortcuts import HttpResponse from django.utils.deprecation import MiddlewareMixin class M1(MiddlewareMixin): def process_request(self,request): print('中间件: M1.process_request') def process_response(self,request,response): print('中间件:M1.process_response') return response def process_view(self,request,callback,args,kwargs): print('中间件:M1.process_view') class M2(MiddlewareMixin): def process_request(self,request): print('中间件:M2.process_request') def process_response(self,request,response): print('中间件:M2.process_response') return response def process_view(self,request,callback,args,kwargs): print('中间件:M2.process_view') print('callback:',callback) class M3(MiddlewareMixin): def process_request(self,request): print('中间件:M3.process_request') def process_response(self,request,response): print('中间件:M3.process_response') return response def process_view(self,request,callback,args,kwargs): print('中间件:M3.process_view') 前端显示视图函数test返回的:ok 后端输出结果如下: 中间件: M1.process_request 中间件:M2.process_request 中间件:M3.process_request 中间件:M1.process_view 中间件:M2.process_view callback: <function test at 0x00000000045A8A60> 中间件:M3.process_view 视图函数:views.test 中间件:M3.process_response 中间件:M2.process_response 中间件:M1.process_response 依结果得出执行流程如下: 执行流程3 3.1 将上述中间件代码中M3.process_request()返回一个HttpResponse(其余代码不变): class M3(MiddlewareMixin): def process_request(self,request): print('中间件:M3.process_request') return HttpResponse('前端显示:中间件:M3.process_request') def process_response(self,request,response): print('中间件:M3.process_response') return response def process_view(self,request,callback,args,kwargs): print('中间件:M3.process_view') 前端页面显示: 前端显示:中间件:M3.process_request 后端输出结果如下: 中间件: M1.process_request 中间件:M2.process_request 中间件:M3.process_request 中间件:M3.process_response 中间件:M2.process_response 中间件:M1.process_response 从输入结果,可以得到如下执行流程: 执行流程4 从上述结果中可以看出,当process_request()返回HttpResponse时,就不再执行process_view()了。process_view()的callback参数是被执行的视图函数对象。 3.2 M2.process_view()返回HttpResponse,M3.process_request()返回None,其余代码不变: 注意:函数没有返回值时,默认返回None。 class M2(MiddlewareMixin): def process_request(self,request): print('中间件:M2.process_request') def process_response(self,request,response): print('中间件:M2.process_response') return response def process_view(self,request,callback,args,kwargs): print('中间件:M2.process_view') return HttpResponse('前端显示:中间件:M2.process_view') 前端页面显示: 前端显示:中间件:M2.process_view 后端输出结果如下: 中间件: M1.process_request 中间件:M2.process_request 中间件:M3.process_request 中间件:M1.process_view 中间件:M2.process_view 中间件:M3.process_response 中间件:M2.process_response 中间件:M1.process_response 从上述结果可以得出如下执行流程: 执行流程5 从上图中可以看出,当中间某一个中间件的process_view()返回HttpResponse时,就不再执行下面中间件的process_view()和视图函数了。 4. 加入process_exception()方法 此方法是当视图函数中抛出异常时执行,当返回None时,前端页面会抛出一个异常页面,当返回HttpResponse时,前端页面会显示你定制的内容。 from django.shortcuts import HttpResponse from django.utils.deprecation import MiddlewareMixin class M1(MiddlewareMixin): def process_request(self,request): print('中间件: M1.process_request') def process_response(self,request,response): print('中间件:M1.process_response') return response def process_view(self,request,callback,args,kwargs): print('中间件:M1.process_view') # return HttpResponse('M1.process_view') def process_exception(self,request,exception): print('中间件:M1.process_exception') class M2(MiddlewareMixin): def process_request(self,request): print('中间件:M2.process_request') # return HttpResponse('前端显示:中间件:M2.process_request') def process_response(self,request,response): print('中间件:M2.process_response') return response def process_view(self,request,callback,args,kwargs): print('中间件:M2.process_view') # return HttpResponse('前端显示:中间件:M2.process_view') def process_exception(self,request,exception): print('中间件:M2.process_exception') class M3(MiddlewareMixin): def process_request(self,request): print('中间件:M3.process_request') # return HttpResponse('前端显示:中间件:M3.process_request') def process_response(self,request,response): print('中间件:M3.process_response') return response def process_view(self,request,callback,args,kwargs): print('中间件:M3.process_view') # return HttpResponse('前端显示:中间件:M3.process_view') def process_exception(self,request,exception): print('中间件:M3.process_exception') 故意给视图函数test加一个错误: def test(request): int('abc') #将字母转换成整型一定会抛出异常 print('视图函数:views.test') return HttpResponse('ok') 前端页面显示如下图: 前端错误页面 4.1 将上述中间件代码中的M2.process_response()返回HttpResponse class M2(MiddlewareMixin): def process_request(self,request): print('中间件:M2.process_request') def process_response(self,request,response): print('中间件:M2.process_response') return response def process_view(self,request,callback,args,kwargs): print('中间件:M2.process_view') def process_exception(self,request,exception): print('中间件:M2.process_exception') return HttpResponse("500错误") 前面页面显示: 500错误 后端输出结果: 中间件: M1.process_request 中间件:M2.process_request 中间件:M3.process_request 中间件:M1.process_view 中间件:M2.process_view 中间件:M3.process_view 中间件:M3.process_exception 中间件:M2.process_exception 中间件:M3.process_response 中间件:M2.process_response 中间件:M1.process_response 执行流程如下图: 执行流程6 从上图可以看出,当中一个中间件的process_exception()方法捕获到视图函数中抛出异常的后并返回HttpResponse,则前端页面就显示你自定制的内容。后端程序也不会出现异常。并且前面的中间件process_exception()也不再执行。 五、中间件应用场景 由于中间件工作在 视图函数执行前、执行后(像不像所有视图函数的装饰器!)适合所有的请求/一部分请求做批量处理 1、做IP限制 放在 中间件类的列表中,阻止某些IP访问了; 2、URL访问过滤 如果用户访问的是login视图(放过) 如果访问其他视图(需要检测是不是有session已经有了放行,没有返回login),这样就省得在 多个视图函数上写装饰器了! 3、缓存(还记得CDN吗?) 客户端请求来了,中间件去缓存看看有没有数据,有直接返回给用户,没有再去逻辑层 执行视图函数

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

Objective-C 学习第六天

一、 内存管理 内存的作用: 存储数据. 1). 如何将数据存储到内存之中 声明1个变量,将这个数据存储进去 2). 当数据不再被使用的时候,占用的内存空间如何被释放 内存中的五大区域 栈:局部变量,当局部变量的作用域被执行完毕之后,这个局部变量就会被系统立即回收. 堆:OC对象,使用C函数申请的空间 BSS段:未初始化的全局变量、静态变量,一旦初始化就回收,并转存到数据段中. 数据段:已经初始化的全局变量、静态变量,知道程序结束的时候才会被回收. 代码段:代码,程序结束的时候,系统会自动回收存储在代码段中的数据. 栈、BSS段、数据段、代码段存储在它们中的数据的回收,是系统自动完成的. 分配在堆区的OC对象,是肯定需要被回收的. iPhone 内存机制,如果内存占用内存达到40M会受到系统警告,120M会闪退. 存储在堆中的OC对象,系统是不会自动回收的,知道程序结束的时候才会被回收。 内存管理的范围: 只需要管理堆中的OC对象的回收,其他区域中的数据是系统自动管理的. 对象应该什么时候被回收? 当有人使用这个对象的时候,这个对象就不会被回收,只有在没有人使用的时候才可以被回收. 引用计数器 1). 每一次对象都有一个属性,叫做retainCount(引用计数器),类型是unsigned long占据八个字节。 引用计数器的作用: 用来记录这个对象有多少人在使用它,默认情况下,创建一个对象出来,这个引用计数器的默认值是1. 2). 当多一个人使用的时候,这个引用计数器的值+1 3). 当少一个人使用的时候,这个引用计数器的值-1 4). 当这个对象的引用计数器变为0的时候,代表这个无人使用,系统就会自动回收它. 如何操作引用计数器 1). 为对象发送1条retain消息,对象的引用计数器就会加1,当多一个人使用的对象的时候才发 2). 为对象发送1条release消息,对象的引用计数器就会减1,当少一个人使用的对象的时候才发 3). 为对象发送一条retainCount消息,就可以了取到对象的引用计数器的值 4). 当对象的引用计数器变为0的时候,对象就会被系统立即回收, 在对象被回收的时候,会自动调用对象的dealloc方法. 内存管理的分类 1).MRC(Manual Reference Counting)手动引用计数,手动内存管理. 当多一个人使用对象的时候,要求程序员手动的发送retain消息;反之. 2). ARC(Automatic Reference Counting)自动引用计数,自动内存管理. 系统自动的在合适的地方发送retain realse消息. 学习MRC理由:面试、早期的App开发使用的是MRC技术、ARC是基于MRC的. 二、MRC Xcode默认的开发方式是ARC模式. 关闭ARC:Project->选中工程->Build Settings-> All->Apple LLVM7.0 - Language - Objective C ->Objective-C Automatic Reference Counting,设置为NO. 当对象的引用计数器变为0的时候,系统会自动回收对象. 在系统回收对象的时候,会自动的调用对象的dealloc方法. 1). 重写类的dealloc方法, 必须要调用父类的dealloc方法,要放在最后一句代码的位置。 - (void)dealloc{ NSLog(@"名字叫XXX消失了"); [super dealloc]; } 测试引用计数器 1). 新创建一个对象,这个对象的引用计数器的值默认是1. Person *p1 = [[Person alloc] init]; [p1 retainCount];// 获取引用计数器的值 [p1 retain];//为引用计数器加1 [p1 release];//为引用计数器减1 2). 当对象的引用计数器变为0的时候,对象就会被系统立即回收,并自动调用dealloc方法. 3). 为对象发送这个return消息,对象的引用计数器就会加1 为对象发送release消息并不是回收对象,而是让对象的引用计数器减1,当对象的引用计数器的值变为0的时候,对象才会被系统立即回收. 内存管理的重点 1). 什么时候为对象发送retain消息 当多一个人使用这个对象的时候,应该先为这个对象发送retain消息 2). 什么时候为对象发送release消息 当少一个人使用这个对象的时候,应该为这个对象发送一条release消息 在ARC机制下,retain、release、dealloc这些方法无法调用 内存管理的原则 1). 有对象的创建,就要匹配一个release 2). retain和release的调用次数要匹配 3). 谁用谁retain,谁不用谁release 4). 只有在多一个人用的时候才retain,少一个人使用的时候才release,有始有终,有加就有减。 野指针 C语言中的野指针: 定义一个指针变量,没有初始化,这个指针变量的值时一个垃圾值,指向一块随机的空间 OC中的野指针:指针指向的对象已经被回收了. 内存回收的本质: 申请一个变量,实际上就是向系统申请指定字节数的空间,这段空间就不会分配给别人了,当变量被回收的时候,代表变量占用的字节空间可以分配给别人了,但是这个字节空间中存储的数据还在。 对象回收的本质:指的是对象占用的空间可以分配给别人了,当这个对象占用的空间没有分配给别人之前,其实对象数据还在. 僵尸对象 1个已经被释放的对象,但是这个对象所占空间还没有分配给别人。通过野指针访问僵尸对象的时候,有可能没问题,也有可能有问题。当僵尸对象占用的空间还没有分配给别人使用的时候,还是可以的;反之。 我们认为只要对象成为了僵尸对象,无论如何都应该不允许访问了。如果访问的是僵尸对象,无论如何都报错。 僵尸对象的实时检查机制,可以将这个机制打开,打开之后,只要访问的是僵尸对象,无论空间是否分配,就会报错。 停止运行按钮右侧的Target切换点击-> Edit Scheme...->Run->Diagnostics->勾选Enable Zomble Objects. 为什么不默认打开僵尸对象检测 一旦打开僵尸对象检测,那么在每访问一个僵尸对象的时候,都会先检测这个对象是否是一个僵尸对象,这样是极其消耗性能的. 如何避免僵尸对象错误? 当一个指针成为野指针以后,将这个指针的值设置为nil. 当一个指针为nil时,通过这个指针调用对象的方法的时候,不会报错,只是没有任何反应,但是如果通过指针直接访问属性就会报错. 无法复活一个僵尸对象 三、 内存泄漏 指的是一个对象没有被及时的回收,在该回收的时候没有及时回收,一直驻留在内存中,知道程序结束的时候才结束. 单个对象的内存泄漏情况 1). 有对象的创建,而没有对应的release 2). retain的次数和release的次数不匹配 3). 在不适当的时候为指针赋值为nil 4). 在方法中为传入的参数不适当的retain 如何保证单个对象可以被回收 1). 有对象的创建,就必须要匹配一个release 2). retain和release次数一定要匹配 3). 只有在指针成为野指针时才赋值为nil 4). 在方法中不要随意的为传入的对象retain 多个对象的内存管理 1). 当属性是一个OC对象的时候,setter方法的写法. 将传进来的对象赋值给当前对象的属性,代表传入的对象多一个人使用,所以我们应该先为这个传入的对象发送一条retain消息再赋值.当当前对象销毁的时候,代表属性指向的对象少一个人使用,就应该在dealloc中release. 代码写法: - (void)setCar:(Car *)car{ _car = [car retain]; } - (void)dealloc{ [_car release]; [super dealloc]; } 2). 当属性是一个OC对象的时候,setter方法按照上面写还是有bug. 当为对象的这个属性多次赋值的时候,就会发生内存泄漏,发生泄漏的原因: 当为属性赋值的时候,代表就对象少一个人用,新对象多一个人用,应该release,旧对象retain新的. 代码写法: - (void)setCar:(Car *)car{ [_car release]; _car = [car retain]; } - (void)dealloc{ [_car release]; [super dealloc]; } 3). 出现僵尸对象的原因,新旧对象是同一个,当发现新旧对象是同一个的时候,什么都不用做.只有当新旧对象不是同一对象的时候,才release旧的. 最终代码写法: - (void)setCar:(Car *)car{ if(_car != car){ [_car release]; _car = [car retain]; } } - (void)dealloc{ [_car release]; [super dealloc]; } 4). 特别注意: 内存管理的范围是OC对象,这个属性的setter方法才要像上面那样写. @property参数 1). 作用 a. 自动生成私有属性 b. 自动生成这个属性的getter/setter的声明 c. 自动生成这个属性的getter/setter的实现 特别播报: 生成的setter方法实现中,无论什么类型,都是直接赋值. 2). @property参数 a. @property可以带参数 @property(参数1, 参数2, 参数3...)数据类型 名称; b. @property的四组参数 a). 与多线程相关的两个参数 atomic/nonatomic b). 与生成的setter方法的实现相关的参数 assign/retain c). 与生成只读、读写相关的参数 readonly/readwrite d). 与生成getter/setter方法名相关的参数 getter/setter 3). 与多线程相关的参数(atomic/nonatomic) atomic: 默认值,这个时候生成的setter方法的代码就会被加上一把线程安全锁.特点: 安全、效率低 nonatomic: 生成的setter方法的代码不会加线程安全锁,但是效率高. 建议要效率,选择使用nonatomic 4). 与生成的setter方法的实现相关的参数(assign/retain) assign: 默认值,生成的setter方法实现就是直接赋值 retain: 生成的setter方法的方法实现就是标准的MRC内存管理代码,先判断新旧对象是否为同一对象,如果不是就release旧的,retain新的. 当属性的类型是OC对象类型的时候就使用retain,当属性的类型实时非OC对象的时候就使用assign. 注意: retain只是生成标准的setter方法为标准的MRC内存管理代码,不会自动的在dealloc中生成release的代码,需要手动添加. 5). 与生成只读、读写相关的参数readonly/readwrite) readwrite: 默认值,代表同时生成getter/setter readonly: 只会生成getter,不会生成setter 6). 与生成getter/setter方法名相关的参数(getter/setter) 默认情况下: @property生成的getter/setter是标准类型的,其实我们可以通过参数来指定@property生成的方法的名字 setter: setter=setter方法名字 用来指定@property生成的setter的方法的名字,注意,setter方法是带参数的,要加一个冒号 getter: getter=getter方法名字 用来指定@property生成的getter方法的名字 注意: 如果使用setter/getter修改了生成方法的名字,在使用点语法的时候,编译器在转换的时候转换成修改后的名字的代码. 使用建议: a. 无论什么情况都不要改setter方法的名字,默认情况下生成的名字已经是最标准的了 b. 什么修改getter方法的名字,当属性的类型是一个BOOL类型的时候,就修改这个getter的名字以is开头,提高代码的阅读性. @class 1). 当两个类相互引用的时候,当Person.h中包含Book.h,而Book.h中又包含Person.h,这个时候就会造成无限递归,而导致无法编译通过. 2). 解决方案: 其中一个类中不要使用#import引入对方的头文件,而是使用@class 类名,来标注这是一个类,这样就可以在不引入对方头文件的情况下,告诉编译器这是一个类。 在.m文件当中再#import对方的头文件 3). @class与#import的区别 a. #import是将指定的文件的内容拷贝到写指令的地方 b. @class并不会拷贝任何内容,只是告诉编译器这是一个类,这样编译器在编译的时候才可以指定这是一个类。 循环retain 1). 当两个对象相互引用的时候 A对象的属性是B对象,B对象的属性是A对象.如果两边都使用retain,就会发生内存泄漏 2). 解决方案 一段使用retain,一段使用assign,使用assign的那一段在dealloc中不再需要release.

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

Objective-C 学习第三天

封装 一、 什么是错误 一般情况下,错误是指源代码不符合语法规范,然后编译报错 后果: 程序无法编译 什么是Bug? 程序可以编译、链接、执行,但是程序执行的结果不是我们预想的。 解决: 通过调试寻找发生Bug的原因. 异常 程序可以编译、链接、执行,当程序在执行的时候,处于某种特定的条件下,程序就会终止。 后果: 程序立即终止运行 如何处理异常 1). 目的: 为了让程序在执行的时候如果发生了异常而不崩溃 2). 语法 @try{ }@catch(NSException *ex){ } 将有可能发生异常的代码放在@try中. 当@try中的代码在执行的时候,如果发生了异常,不会奔溃,而是立即跳到@catch中执行代码。 当@catch的代码执行完毕后,结束@try...@catch往下执行. 如果没有发生异常, 则跳过@catch往下执行. 3). 当@try中的代码在执行的时候发生了异常,@try块发生异常后面的代码不会被执行. @catch中的代码只有在@try的代码发生异常的时候才会被执行,所以@catch中我们一般情况下写处理异常的代码. @catch的参数NSException *ex通过%@打印出ex指向对象的值,可以拿到发生异常的原因 @try...@catch后面还可以跟1个@finally块 ``` @try{ }@catch(NSException *ex){ }@finally{ } ``` @try...@catch并不是万能的, 并不是所有的运行时错误都可以处理的。 类方法 0). 在一个Target中无法访问另外一个Target中的方法. 1). OC中的方法分为两种 a. 对象方法/实例方法 想要调用对象方法就必须要先创建对象,然后调用 b. 类方法 类方法的调用不依赖于对象. 如果要调用类方法,不需要创建对象 2). 类方法声明 a. 对象方法的声明: 对象方法的声明 - 号 - (返回值)方法名; - (void)sayHi; b. 类方法的声明: 类方法声明使用 + 号 + (返回值类型)方法名; 3). 调用 a. 对象方法: 先创建对象再通过对象名来调用 b. 类方法: 不需要创建对象, 直接使用类名来调用 [类名 类方法名]; 4). 分析类方法和对象方法 a. 类方法的特点 a). 节约空间 b). 提高效率 5). 在类方法中不能直接访问属性 因为属性只有在对象创建的时候才会创建在对象之中,而类方法在执行的时候有可能还没有对象。 虽然不能直接访问属性,但是我们可以在类方法中创建一个对象访问这个对象 a. 属性是在对象创建的时候跟随着对象一起创建在对象之中 b. 类第1次在访问时回做类加载 在类方法中不能使用self来调用其他对象方法 [self 方法名];//调用当前类型的方法 在对象方法当中可以调用类方法 [类名 方法名]; 什么时候可以将方法定义为类方法 如果方法不需要直接访问属性,也不需要直接调用其他的对象方法,可以定义为类方法 关于类方法的规范. 1). 如果我们写一个类,要求为这个类提供一个与类名同名的方法,这个方法创建 创建一个纯净的对象返回. 苹果和第三方都遵守这个规范 (Person *)person; 2). 如果希望创建的对象的属性的值由调用者指定,那么这个类方法带参数. 类名WithXXX:... (Person *)personWithName:(NSString *)name andAge:(int)age; 二、 NSString 是1个数据类型,用来保存OC字符串的 其实NSString是Foundation框架中的1个类,作用存储OC字符串.所以OC中的字符串本质上是用NSString对象来存储的. 完整的标准的创建NSString对象的方式 NSString *str = [NSString new]; NSString *str1 = [NSString string]; 这种方式创建的字符串是空字符串 @"" 但是NSString是最常用的1个对象, 所以OC使用了1种更为简单的方式来创建对象,直接使用@来表示1个OC字符串. NSString *str = @"jack"; @"jack" 本质上是一个NSString对象,str是这个对象的地址. NSString最常用的类方法 1). + (instancetype)stringWithUTF8String:(const char *)nullTerminatedCString instancetype作为返回值,代表返回当前这个类的对象 char *str0 = "rost"; NSString *str1 = [NSString stringWithUTF8String:str0]; 2). + (instancetype)stringWithFormat:(NSString *)format, ...使用频率非常高 作用: 拼接1个字符串对象,使用变量或者其他数据拼接成OC字符串 int age = 19; NSString *name = @"小明"; [NSString stringWithFormat: @"大家好,我叫%@, 我今年%d岁.",name,age] 最长用的对象方法 1). length方法, 返回值NSUInteger,计算字符串长度 NSString *str = @"itcast"; NSUInteger len = [str length]; 2). 得到字符串中指定下标的字符 (unichar)characterAtIndex:(NSUInteger)index; 返回值是unichar, 其实就是unsigned short,占据两个字节. 如果要输出unichar变两个的值使用%C NSString *str = @"itcast"; unichar ch = [str characterAtIndex:2]; 3). 判断两个字符串是否相同 a. 判断两个字符串内容是否相同, 不要使用==判断 b. 判断相等的方式 - (BOOL)isEqualToString:(NSString *)aString; 判断两个字符串是否相等应该使用上面的方法来判断. NSString *str1 = @"jack"; NSString *str2 = @"jack"; [str1 isEqualToString: str2]; 4). 判断两个字符串大小 - (NSComparisonResult)compare:(NSString *)string; NSComparisonResult是个枚举, 完全可以使用int来接收返回值. NSString *str1 = @"jack"; NSString *str2 = @"jack"; [str1 compare: str2]; 匿名对象 1). 之前创建对象的做法: Person *p1 = [Person new]; 让1个指针指向1个对象 2). 匿名对象 没有名字的对象, 如果我们创建一个对象,没有用1个指针存储这个对象的地址,也就是没有任何指针指向这个对象,那么这个对象就叫做匿名对象. 3). 如何使用1个匿名对象 [Person new]->_name = @"jack"; [[Person new] sayHi]; 4). 注意点 a. 匿名对象只能使用一次 b. 每次创建匿名对象都是不同的对象 5). 使用情况 a. 某个对象只会被使用一次 b. 如果方法的参数是一次对象, 并且这个对象调用者不会使用 三、 面向对象的三大特征: 封装、继承、多态 封装: a. 函数就是封装的体现 b. 类就是更高级别的封装 好处: ->屏蔽内部的实现, 外界不需要知道内部是如何实现的 ->方便操作 继承: 多态: setter封装 1). 将属性的@public去掉, 一旦写上@public就可以直接访问对象的这个属性. 为类提供1个方法,专门为这个属性赋值,这个方法我们叫做setter。 a. 这个方法一定是1个对象方法 b. 没有返回值 c. 这个方法的名称必须以set开头, 跟上去掉下划线首字母大写的属性名. d. 这个方法一定是有参数的, 参数的类型和属性的类型一致, 参数的名称和属性的名称一致(去掉下划线) e. 在方法的实现中,检测传入的数据是否符合要求 // 声明 @interface Person : NSObject{ int _age; } - (void) setAge(int age); @end // 实现 @implementation Person - (void) setAge(int age){ _age = age; } @end // 调用 Person *p = [Person new]; [p setAge:10]; getter封装 1). 用来取出属性的值 a. 这个方法一定是一个对象方法 b. 这个方法返回值类型和属性的类型一致 c. 这个方法的名称直接属性的名称(去掉下划线) d. 这个方法没有参数 e. 外界想要获取这个值,直接调用方法即可. // 声明 @interface Person : NSObject{ int _age; } - (void) setAge(int age); - (int)age(); @end // 实现 @implementation Person - (void) setAge(int age){ // 可以做验证 _age = age; } - (int)age(){ return _age; } @end // 调用 Person *p = [Person new]; [p setAge:10]; [p age]; 注意 属性的@public一定要去掉 判断参数的值是否符合逻辑 getter/setter方法名极度不规范 什么时候需要封装getter/setter 1). 只要属性需要被外界访问就要回这个属性封装setter和getter, 就算赋值或者取值的时候没有任何逻辑验证 2). 如果属性只在内部访问, 不需要封装getter/setter 只读只写封装 只读封装: 为属性封装的时候,只提供getter属性 只写封装: 为属性封装的时候,只提供setter属性 对象之间的关系 1). 组合关系: 一个类是由其他几个类组合而成的 2). 依赖关系: 一个对象的方法的参数是另外一个类 a. 耦合度: 当一个类修改之后另一个类无法使用,叫高耦合 b. 低耦合:当一个类修改之后另一个类正常使用,叫高耦合 c. 高内聚: 一个对象仅仅只做自己相关的事情 d. 单一职责原则: 一个类只做自己的事情 3). 关联关系: 两个类之间语义级别的一种强依赖关系, 拥有关系 4). 继承关系:

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

Objective-C 学习第四天

一、 Xcode文档的安装 1). Xcode文档提供了很多框架, 框架当中有很多类和函数, 提供的一些数据类型. 2). Xcode文档需要单独安装. a. 在线安装: Xcode-> Preferences...->Downloads->Xcode文档 b. 离线安装: 路径:/Applications/Xcode.app/Contents/Developer/Documentation/DocSets/ 点击Window->Documentation and API Reference. static 关键字 1). C语言中的static a. 修饰局部变量: 把局部变量变成静态变量 b. 修饰全局变量 c. 修饰函数 2). OC中的static a. static不能修饰属性也不能修饰方法 b. 可以修饰方法中的局部变量 如果方法中的局部变量被static修饰, 这个变量就会被变成静态变量.存储在常量区 self关键字 1). 方法的内部可以定义一个与类属性相同的变量, 这个时候如果在方法中访问这个同名的变量, 则访问的是局部变量. 2). self: 自己的. 和Java、C#中的this关键字有点像. 可以在对象方法和类方法中使用. self是1个指针, 在对象方法中self指向当前对象, 在类方法中self指向当前类. 3). self用在对象方法中 a. self在对象方法中, 指向当前对象 b. 可以使用self显示的调用当前对象的属性 c. 可以使用self来调用当前对象的其他对象方法 NSLog(@"self = %p", self); NSLog(@"_name = %s", self->_name); [self hehe]; d. 必须使用self场景 a). 如果在方法当中存在和属性同名的局部变量,如果想要访问同名的局部变量,直接写就可以了,如果想要访问当前对象的同名属性,必须使用self b). 在对象方法中,如果要调用当前对象的对象方法必须使用self e. 选用self场景 如果这个时候想要访问对象的属性, 可以选择性使用. f. 属性要求以下划线开头, 局部变量不要求以下划线开头. 4). 把self用在类方法中 a. 类加载:当类第1次被访问的时候,会将类的代码存储在代码区 b. 在类方法中, self也是一个指针,指向当前类 c. 获取类在代码段中的地址 a). 调试, 获取isa指针 b). 在类方法中查看self值 c). 调用对象的对象方法class d). 调用类的类方法class d. 可以用self调用本类中的其他类方法 5). 对象方法可以声明多次,但只能实现一次. 对象方法和类方法可以重名. 6). 注意 a. 在对象方法中可以通过self访问当前对象成员, 不能使用self调用本类中的类方法 b. 在类方法中, 可以使用self调用当前类中的其他类方法.不能使用self访问对象成员. 继承 1). 继承的目的: 子类想拥有父类中的所有成员 2). 语法 ``` @interface 类名 : 父类 @end ``` 3). 效果: 子类拥有了父类的所有的成员 4). 术语 @interface Student : Person{ } Student类从Person类继承,Student类是Person类的子类, Person类是Student类的父类. 5). 在新创建类模块的时候指定父类, Xcode自动完成 6). 继承是类在继承,而不是对象在继承. 创建的对象与对象之间没有任何关系. 7). 继承的时候不要乱继承. 凡是满足is a关系的类,就可以拥有继承的关系. 8). 如果有1个成员不是所有子类都拥有,那么这个成员就不应该定义在父类之中 二、 继承的特性 1). 单根性: 一个类只能有两个父类 2). 传递性: A类从B类继承,B类从C类集成 NSObject类 是Foundation框架中的类.在这个类中有1个类方法new,这个方法是用来创建对象的,方法的返回值是创建这个对象的指针. 如果我们想要让类具备创建对象的能力,就必须直接或者间接的要从NSObject类继承. 在NSObject类中,有一个属性叫isa指针. NSObject类是OC中所有类的祖宗类. 子类不能存在和父类同名的属性. super关键字 1). 可以用在类方法和对象方法中 2). 在对象方法中可以使用super关键字调用从父类继承过来的方法 3). 在类方法中 super关键字可以调用从父类继承过来的类方法 a. 类方法也能被子类继承, 可以使用子类调用也可以使用父类调用 b. 在子类的类方法中,可以使用super关键字调用父类的类方法 4). super不能访问属性,只能调用父类的对象方法或者类方法 访问修饰符 1). 用来修饰属性,可以限定对象可以在哪一段访问 2). 修饰符 @private: 私有,仅允许本类访问 @protected: 受保护的,允许本类及子类访问 @package: 被@package修饰的属性可以在当前框架中访问 @public: 公共的,可以在任意地方访问 3). 默认属性为@protected 4). 子类可以继承子类的私有属性,只是无法访问 5). 如果父类有一个方法为属性赋值或者取值,子类可以间接的访问这个属性 6). 使用建议 a. @public 无论什么情况下都不要使用,属性不要直接暴露给外界 b. @private 如果属性只想在本类中使用不想在子类中使用,就使用她 c. @protected 本类及子类使用 d. 推荐使用默认的@protected 7). 访问修饰符只能用来修饰属性, 不能用来修饰方法 私有属性和方法 1). @private修饰的属性叫做私有属性,只能在类的内部访问,但是在外界的时候Xcode仍然会提示这个属性,只不过没有权限访问. 2). 在@implementation中写一个大括弧,把属性定义在@implementation中做到真私有,外界无法看到。访问修饰符无效. 将属性定义在@implementation之中和将属性定义在@interface中并标记为@private的区别是提示与不提示,都不能在外界访问. 示例: //实现 @implementation Person{ int num;// 真私有 } @end 3). 私有方法 方法只写实现不写声明即可做到方法私有,只能在本类的其他方法中调用,不能在外界调用 1). 里氏替换原则(LSP):子类可以替换父类的位置,并且功能不受影响 a. 父类指针迫切的需求1个父类对象,而我们给了1个对象完全没有问题,因为子类就是1个父类. b. 因为父类中拥有的成员子类都有,所以不会影响程序的功能 2). 里氏替换原则的变现形式 a. 当1个指针指向1个子类对象的时候 3). 作用: a. 一个指针不仅可以存储本类对象的地址还可以存储子类对象的地址 b. 如果1个指针的类型是NSObject类型的,那么这个指针可以存储任意的OC对象地址. c. 如果一个指针数组是NSObject类型的,那么它可以存任意指针. d. 如果一个方法的参数是一个对象,那么我们可以为这个参数传递本类对象或者子类对象 4). 当一个父类指针指向指向一个子类对象的时候,通过父类指针只能调用这个子类对象当中的成员. 5). 方法的重写 a. 直接在子类的实现中将这个方法重新实现一遍 b. 当父类指针指向1个子类对象的时候.通过父类指针调用的方法,如果子类重写了,那么调用的就是子类的方法. 多态 指的是同一个行为,对于不同的事物具有完全不同的表现形式. description 1). %p 打印的是指针变量的值 %@ 打印的是指针指向的变量 2). 使用%@打印1个对象 输出的格式: <对象所属的类名: 对象的地址> 3). 原理 当使用%@打印1个对象的时候,NSLog的底层实现, 调用传入的对象的description方法, 拿到这个方法的返回值, 将这个字符串输出. 4). description方法是定义在NSObject类之中的. 实现: 返回的字符串格式@"<对象所属类名:对象的地址>" 5). 重写description方法(类似于Java中的toString方法) - (NSString *)description{ return [NSString stringWithFormat:@"姓名"]; } 6). 如果你希望%@打印一个对象的时候,对象的格式我们自己指定

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

hive(让我凌乱的一天)

子查询 有两种 一种是在from中在from中相当于省去一张字段表 SELECT ... FROM(subquery)name... SELECT col FROM ( SELECT a+b AS col FROM t1) SELECT t3.olROM ( SELECT a+b AS col FROM t1 UNION ALL SELECT c+d AS cal FROM t2 ) t3 另外一种是在where中操作在where中的子查询相当于条件单字段 所以做不了多字段表(纯属个人理解) SELECT * FROM AWHERE A.a IN (SELECT foo FROM B); 其他支持的types 有 EXISTS and NOT EXISTS SELECT AFROM T1WHERE EXISTS(SELECT B FROM ).....

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

玩Android的第一天

发现从网上下载的Android源代码无法运行,提示"Android Level 7 unable"原来是我没有安装对应的SDK,之前听大树说只要安装几款主流的sdk就可以了,但是我们看别人的源代码的时候,需要安装更多的sdk,所以我还是把所有的sdk都安装了。 虚拟机:在elicpse下面启动虚拟机是一个漫长的过程,建议开了Android的虚拟机就不要关闭了,不然很痛苦。 android:layout_width="60dpi"这段代码提示 Description Resource Path Location Type error: Error: No resource found that matches the given name (at 'scr' with value '@drawable/icon'). addnew.xml /Android_Contactor/res/layout line 20 Android AAPT Problem 为什么出错了,百度上的答案很奇怪,也不能解决我的问题。实在1.6下面的。 本文转自陈哈哈博客园博客,原文链接http://www.cnblogs.com/kissazi2/archive/2012/01/21/2977156.html如需转载请自行联系原作者 kissazi2

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

老板点赞的90天AI落地法!

当下很多企业推进 AI 落地,很容易陷入量化误区:统计上线了多少智能体 Agent、完成多少场员工 AI 培训、产出多少 Demo 原型,把这些指标当成 AI 转型的成绩单。但大量实践告诉我们,Agent 数量、培训场次不等于真实业务价值。热闹过后,大部分智能体束之后,员工学完工具依旧沿用旧的工作习惯,AI 停留在演示层面,无法渗透到真实业务流程当中。

资源下载

更多资源
腾讯云软件源

腾讯云软件源

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

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

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

用户登录
用户注册