Objective-C 学习笔记 | 基础

news2024/11/23 18:51:02

Objective-C 学习笔记 | 基础

参考书:《Objective-C 编程(第2版)》

第1部分 入门

Objective-C语言是以C语言为基础的,但增加了对面向对象编程的支持。Objective-C语言是用来开发在苹果iOS以及OS X操作系统上运行的应用的编程语言。

第2部分 如何编程

该部分讲解了C语言编程的必要知识,这里只记录Objective-C新增内容。

NSInteger和NSUInteger

NSUInteger是无符号的整型,NSInteger是有符号的整型。

NSInteger是一个封装,它会识别当前操作系统的位数,自动返回最大的类型。
定义的代码类似于下:

#if __LP64__ || TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif

这样做让NSInteger和NSUInteger变得通用,不用考虑设备是32位还是64位。

如果使用printf()来输出这两种类型的变量,需要先将NSInteger转换成long,NSUInteger转换成unsigned long。

第3部分 Objective-C与Foundation

该部分开始介绍Objective-C。编写Objective-C程序时,要使用Foundation框架。框架(framework)是由很多类(Class)组成的库。这里记录一些新的知识点。

#import和#include的区别

#include指令告诉编译器做呆板的复制粘贴,将包含的内容粘贴到目标文件中来。而#import指令则让编辑器先检查之前是否导入过这个文件,或是已经被包含到目标文件中了。因此,#import指令导入更快、更有效率。

类与实例、方法与消息

Objective-C也有类和对象的概念,Objective-C的方法和消息与函数类似。如需执行方法中的代码,首先需要发送一条消息给包含这个方法的对象或类。消息发送(指令)必须写在一对方括号中,并且必须包含接收方(receiver)和选择器(selector),如下图所示:

请添加图片描述

date是一个类方法。date方法执行后,NSDate类会在堆上new一个NSDate实例:now,并初始化为当前的日期/时间,然后返回新对象(now)的地址。

请添加图片描述

有了NSDate实例:now之后,我们可以给这个对象发一个实例方法,比如:timeIntervalSince1970。通常来说,实例方法会提供实例中实例变量的信息,或是对实例的实例变量进行操作。

测试程序:

//
//  main.m
//  TimeAfterTime
//
//  Created by 刘文晨 on 2024/6/5.
//

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // 向 NSDate 类发送 date 消息,让它执行 date 方法
        NSDate *now = [NSDate date];
        // 打印实例的地址
        NSLog(@"This NSDate object lives at %p", now);
        // %@ 会输出相应对象的“描述信息”
        NSLog(@"The date is %@", now);
        // 实例方法
        double seconds = [now timeIntervalSince1970];
        NSLog(@"It has benen %f seconds since the start of 1970.", seconds);
    }
    return 0;
}

注意:

  1. 类方法和类对应,实例方法和实例对应。receiver和selector不匹配就会出错。
  2. Objective-C是区分大小写的,方法名也是区分大小写的。
  3. Objective-C语言命名习惯为“驼峰式”或“前缀大写的驼峰式”。

alloc和init

消息可以以嵌套的形式连续发送,而唯一必须要以嵌套的形式发送的消息是alloc和init。

每个类都有一个alloc类方法,它创建一个新的对象并返回指向该对象的指针。通过alloc类方法创建出来的对象,必须要经过初始化才能使用。每个类也都有一个init实例方法,它用来初始化实例。

NSDate *now = [[NSDate alloc] init]; // 消息嵌套,和下面的效果一样
NSDate *now = [NSDate date]; // date 方法代码最少,称之为便利方法

nil

nil就是空指针,不指向任何对象。

在Objective-C中,可以向nil发送消息,是合法的,但得到的返回值没有意义。

注意,如果程序向某个对象发送了消息,但不符合预期,应该检查receiver是否为nil。

id

id 类型的含义是:可以指向任意类型的Objective-C对象的指针。‘

id delegate; // id 已经隐含了 * 的作用

类似于 auto(?)

ARC

ARC(automatic reference counting,自动引用计数)为Objective-C提供了一种自动销毁不被引用的对象的机制。当项目开启了ARC,编译器会自动给项目添加代码来计算每个对象的引用数,即每个对象都会对指向自己的指针计数。当引用数为0时, 程序会自动销毁该对象,释放内存。

类似于 shared_ptr。

在Objective-C加入ARC之前,程序员必须手动维护引用计数。

[anObject release]; // abOject 会失去一个拥有方
[anObject retain]; // abOject 会得到一个拥有方
[anObject autorelease]; // abOject 会在 autorelease 池(对象)被排干(drain)的时候收到 release 消息

虽然 ARC 会自动使用 autorelease 池,但是必须由程序创建并排空相应的 autoreleasepool 池,语法如下:

// 创建 autorelease 池(对象)
@autoreleasepool {
  ...
} // autorelease 池被排空

字面量语法

格式:

NSString *lament = @"Hello World!";
NSArray *dataList = @[now, tomorrow, yesterday]; // 这三个都是 NSDate 对象

字面量语法是Objective-C语言的一种缩写,可以以不明确发送消息的方式创建实例。

还没有字面量语法的时候,只能使用 arrayWithObjects: 类方法来创建NSArray实例:

NSArray *dataList = [NSDate arrayWithObjects:now, tomorrow, yesterday, nil]; // nil 是结束标记,让方法停止运行

self

Objective-C的方法都包含一个隐含的局部变量 self。self 是指针,指向运行当前方法的对象。当某个对象要向自己发送消息时,就需要使用 self。它有 2 个简单的用法:

  1. 调用自身的存取方法,避免直接存取实例变量。
  2. 将 self 作为实参传给其他方法,以便其访问“当前的”对象。

NSObject 协议中的 self:

#include <objc/objc.h>
#include <objc/NSObjCRuntime.h>

@class NSString, NSMethodSignature, NSInvocation;
@protocol NSObject

- (BOOL)isEqual:(id)object;
@property (readonly) NSUInteger hash;
@property (readonly) Class superclass;
......
- (Class)class OBJC_SWIFT_UNAVAILABLE("use 'anObject.dynamicType' instead");
- (instancetype)self;
......
@end

self最终返回的结果就是instancetype类型的代理方法,它是动态类型,最终运行时才会确定,实例方法返回实例类型、静态方法返回的是Class。

super

super 的作用:直接调用父类中的某个方法,或者说从父类开始查找与之匹配的实现。

使用场合:子类重写父类的方法时想保留父类的一些行为。

结构体 objc_super 的官方解释:The compiler generates an objc_super data structure when it encounters the super keyword as the receiver of a message. It specifies the class definition of the particular superclass that should be messaged.

#include <objc/objc.h>
#include <objc/runtime.h>

#pragma GCC system_header

#ifndef OBJC_SUPER
#define OBJC_SUPER

/// Specifies the superclass of an instance. 
struct objc_super {
    /// Specifies an instance of a class.
    __unsafe_unretained id receiver;
    /// Specifies the particular superclass of the instance to message. 
#if !defined(__cplusplus)  &&  !__OBJC2__
    __unsafe_unretained Class class;
#else
    __unsafe_unretained Class super_class;
#endif
};

当遇到super关键字时,编译器会生成一个objc_super结构体,作为消息的接收者,objc_super结构体使得接收消息的父类的定义被明确化。

isa指针

任何一个对象的isa指针都会指向创建该对象的类。

给对象发送消息的时候,对象就会通过isa指针找到该对象的类并查询是否有该消息名的方法。如果没有,就会继续查询它的父类,直到找到名为消息名的方法,或者到达继承链的顶端(NSObject)为止。

description方法和%@转换说明

格式说明符%@让对象描述自己,实际上在处理%@时,程序会向相应的指针变量所指的对象发送 description 消息。

description 方法会返回一个描述类实例的字符串。description 是一个 NSObject 方法,所以所有的对象都有这个方法。默认的 NSObject 实现会以字符串的形式返回该对象在内存的地址。不同的类可以重写(override)description 方法,来最有效地描述实例。

强引用循环和弱引用

两个对象互相拥有的关系将导致相关对象都无法释放,这种情况叫强引用循环,这是导致内存泄露的常见原因。

请添加图片描述

Xcode的Instruments中的Leaks组件可以找出程序中的强引用循环:

请添加图片描述

通过弱引用,可以解决该问题。弱引用是不说明所有权的指针,把 BNRAsset 的 holder 属性改成 weak,就能让 BNRAsset 对象不拥有它的 holder(BNREmployee 对象)。代码如下:

#import <Foundation/Foundation.h>
@class BNREmployee;

NS_ASSUME_NONNULL_BEGIN

@interface BNRAsset : NSObject

@property (nonatomic, copy) NSString *label;
@property (nonatomic, weak) BNREmployee *holder;
@property (nonatomic) unsigned int resaleValue;

@end

NS_ASSUME_NONNULL_END

完整程序见于:UestcXiye/Objective-C-Practice。

弱引用的自动置零特性:强引用会保留对象的拥有方,使其不被释放。而弱引用则不会保留,因此标为弱引用的实例变量与属性指向的对象可能会消失,如果发生了这种情况,那么这个实例变量或属性会被设为 nil。

Collection 类

Collection 类的实例用于保存指向其他对象的指针。主要分为三种:

  1. NSArray 及其子类 NSMutableArray
  2. NSSet/NSMutableSet
  3. NSDictionary/NSMutableDictionary

注意以下 4 点:

  1. Collection 对象只能保存对象的指针,不能保存基本类型变量或指向结构的指针,需要先将这些 C 语言基本类型封装成对象,再存入 Collection 对象。

    例如:float变量、int变量等要先转换成NSNumber再存入Collection对象,或者直接用NSNumber字面量实例。结构可以用NSValue(它是NSNumber的父类)实例来封装。

  2. 其中 NSArray、NSSet、NSDictionary 具有不可修改性。使用它们可以节约内存提高性能,因为它们的 copy 方法仅仅返回指向自己的指针,不会做拷贝之类的事情。

  3. 向可改变的 Collection 对象中加入某个对象时,Collection 对象会成为该对象的拥有方;同理,移除对象时,Collection 对象就不再是该对象的拥有方了。对于不可改变的 Collection 对象而言,创建时就拥有其中所有对象的所有权,而 Collection 对象被释放时,它就放弃其中所有对象的所有权。

  4. Collection 对象不能保存 nil,需要将“空”包装成一个对象,可以使用 NSNull 类。

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

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

相关文章

算法导论实战(三)(算法导论习题第二十五、二十六章)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;算法启示录 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 前言 第二十五章 25.1-10 25.2-5 25…

C++ | Leetcode C++题解之第140题单词拆分II

题目&#xff1a; 题解&#xff1a; class Solution { private:unordered_map<int, vector<string>> ans;unordered_set<string> wordSet;public:vector<string> wordBreak(string s, vector<string>& wordDict) {wordSet unordered_set(w…

【Jenkins】Jenkins - 节点

选择系统设置 - 节点设置 -添加节点 下载对应的 jar包 &#xff0c;执行命令 测试运行节点生效 1. 创建测试项目 test1 2. 选择节点执行&#xff1a; 在配置页面的“General”部分&#xff0c;找到“限制项目的运行节点”&#xff08;Restrict where this project can be run…

Kali Linux 2024.2 释出

渗透测试发行版 Kali Linux 释出了最新的 2024.2。 主要新特性包括&#xff1a;桌面环境更新到 GNOME 46&#xff0c;Xfce 环境加入 HiDPI 模式&#xff0c;更新了网络侦察工具 AutoRecon&#xff0c;监视 Linux 进程的命令行工具 pspy&#xff0c;提取和显示 CVE 信息的 Splo…

现代密码学-基础

安全业务 保密业务&#xff1a;数据加密 认证业务&#xff1a;保证通信真实性 完整性业务&#xff1a;保证所接收的消息未经复制、插入、篡改、重排或重放 不可否认业务&#xff1a;防止通信双方的某一方对所发消息的否认 访问控制&#xff1a;防止对网络资源的非授权访问&…

Mysql使用中的性能优化——索引数对INSERT性能的影响

表的索引可以给数据检索提升效率&#xff0c;但是也给表的增删改操作带来代价。本文我们将关注&#xff0c;索引数量对INSERT操作的影响。 结论 索引数的新增会造成INSERT操作效率下降&#xff0c;约每增一个索引会降低10%效率。 实验数据 可以看到0个索引的效率是7个索引效…

12-C语言的内存管理

12-C语言的内存管理 文章目录 12-C语言的内存管理一、C语言进程的内存布局1.1 程序与进程1.2 虚拟内存与物理内存1.2.1 虚拟内存布局 二、栈空间的特点与管理三、静态变量3.1 全局静态变量3.2 局部静态变量3.3 为什么需要静态变量&#xff1f; 四、数据段与代码段4.1 数据段4.2…

VSCode数据库插件

Visual Studio Code (VS Code) 是一个非常流行的源代码编辑器&#xff0c;它通过丰富的插件生态系统提供了大量的功能扩展。对于数据库操作&#xff0c;VS Code 提供了几种插件&#xff0c;其中“Database Client”系列插件是比较受欢迎的选择之一&#xff0c;它包括了对多种数…

Django 连接mysql数据库配置

1&#xff0c;提前创建注册的app1应用 Test/Test/settings.py python manage.py startapp app1 2&#xff0c;配置mysql数据库连接 Test/Test/settings.py DATABASES {default: {ENGINE: django.db.backends.mysql,# 数据库名字NAME: db1,# 连接mysql数据库用户名USER: ro…

力扣 240.搜素矩阵II

题目描述&#xff1a; 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。每列的元素从上到下升序排列。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,4,7,11,15],[2,5,8,12,19],[3,6,9…

【自动部署】4.阿里云ECS服务器 IDEA自动部署项目

如何在IDEA中,自动部署项目到阿里云ECS服务器?今天我们就来实现一键部署功能。 执行maven命令打包免密登录,在IEDA中连接服务器执行stop服务上传jar包到服务器执行start脚本查看运行日志1.安装Alibaba Cloud Toolkit 2.配置host 3.自动化部署后端 右击项目,选择Alibaba CL…

Java Web学习笔记28——Element案例

案例&#xff1a; 根据页面原型完成员工管理页面开发&#xff0c;并通过Axios完成数据异步加载。 服务端数据获取地址&#xff0c;也就是API接口。 这个URL返回的是JSON格式的数据。 表格就是把JSON格式的数据渲染显示在页面中。 页面分为三个部分: 页头&#xff1a; 菜单…

学习笔记——路由网络基础——直连路由(direct)

二、直连路由(direct) 直连路由(direct)&#xff1a;直接相连&#xff0c;接口配置好ip地址并up后自动生成的路由。默认优先级为0 Destination&#xff1a;表示路由的目的地址。用来标识IP包的目的地址或目的网络。 Mask&#xff1a;表示目的地址的子网掩码长度。 与目的地址…

【创作活动】面对层出不穷的AI大模型产品我们应该怎么选择?

&#x1f604; 19年之后由于某些原因断更了三年&#xff0c;23年重新扬帆起航&#xff0c;推出更多优质博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Mi…

Java | Leetcode Java题解之第139题单词拆分

题目&#xff1a; 题解&#xff1a; public class Solution {public boolean wordBreak(String s, List<String> wordDict) {Set<String> wordDictSet new HashSet(wordDict);boolean[] dp new boolean[s.length() 1];dp[0] true;for (int i 1; i < s.len…

[Vue3:axios]:实现实现登陆页面前后端请求,并用Vite解决跨域问题

文章目录 一&#xff1a;前置依赖查看依赖安装 axios&#xff1a;npm install axios 二&#xff1a;配置文件&#xff1a;创建一个用于全局使用的axios实例&#xff0c;并在main.js或main.ts文件中将其配置为全局属性。根目录mainjs文件引入axios 三&#xff1a;登录页面发送登…

C++中的一些困惑(长期更新中)

C中的一些困惑 文章目录 C中的一些困惑1. using std::具体命名与using namespace std;2. 【int \*p[10] 】与 【int (\*p)[10]】3. main()函数可带参&#xff0c;参从何来&#xff1f;4. constexpr函数的返回值可不为常量&#xff0c;那这时constexpr关键字作用是什么&#xff…

Mybatis03-ResultMap及分页

1、属性名和字段名不一致问题 1.问题 数据库中的字段 新建一个项目Mybatis-04&#xff0c;拷贝之前&#xff0c;测试实体类字段不一致的情况 public class User {private int id;private String name;private String password; }select * from mybatis.user where id #{id} …

计算机网络 ——网络层(IPv4地址)

计算机网络 ——网络层&#xff08;IPv4地址&#xff09; 什么是IPv4地址IP地址的分类特殊的IP地址 查看自己的IPv4地址 我们今天来看IPv4地址&#xff1a; 什么是IPv4地址 IPv4&#xff08;Internet Protocol version 4&#xff09;是第四版互联网协议&#xff0c;是第一个被…

【YOLO系列】YOLOv1学习(PyTorch)原理加代码

论文网址&#xff1a;https://arxiv.org/pdf/1506.02640 训练集博客链接&#xff1a;目标检测实战篇1——数据集介绍(PASCAL VOC&#xff0c;MS COCO)-CSDN博客 代码文件&#xff1a;在我资源里&#xff0c;但是好像还在审核&#xff0c;大家可以先可以&#xff0c;如果没有的…