当前位置:

首页 > 编程开发 > .NET  i18n 原理、实现一个 i18n 框架的过程详解

.NET  i18n 原理、实现一个 i18n 框架的过程详解

基于ASP.NETCore实现的Maomi.I18n多语言框架,通过键值对管理语言资源,支持按项目目录组织JSON文件,编译后统一合并。框架利用RequestLocalizationMiddleware自动解析请求语言,适用于控制台、Web和WPF等场景,实现通用国际化方案。

随着业务的国际化,软件产品需要支持多种语言,这已经成了基本需求——用户选择什么语言,界面就展示什么语言。ASP.NET Core 或 ABP 这类框架虽然都提供了多语言方案,配置方式各不相同,但底层思路其实一样:通过键值对来管理,开发者为每个 key 提供不同语言的值,框架根据请求上下文自动匹配。说白了,就是做个翻译映射表。

今天我们就来聊聊如何基于 ASP.NET Core 实现一个实用的 i18n 多语言框架。最终成品叫 Maomi.I18n,它能同时跑在控制台、ASP.NET Core、WPF 等项目里,还支持自定义多语言资源,算是一套通用方案。

什么是 i18n?

i18n 是 "internationalization"(国际化)的缩写。名字挺有意思——首字母 i 和末字母 n 之间正好隔着 18 个字母,所以就叫 i18n。简单说,i18n = 国际化,就是让应用能适应不同语言和地区的技术。

类似的缩写还有 L10n (localization,本地化),L 和 n 之间有 10 个字母。

i18n vs L10n 的区别

概念英文含义示例
国际化i18n开发时让程序支持多语言的能力使用资源文件、支持 Unicode、处理不同日期格式
本地化L10n针对特定语言/地区进行适配翻译文本、使用本地货币符号、适配当地日期格式

类比一下

  • i18n = 手机充电口设计成 Type-C(通用接口)
  • L10n = 给手机配一个当地规格的充电头

体验 Maomi.I18n

在动手写框架之前,先来感受一下最终成品 Maomi.I18n 怎么用。毕竟,先知道它有多好用,才有动力研究它怎么实现的。

控制台示例

如果要用 json 文件存储语言包,就需要按项目名称创建目录。我们拿一个实际例子走一遍流程。

创建一个 Demo5.Lib 项目,引入 Maomi.I18n 框架。然后在 Demo5.Lib 和 Console 两个项目下都添加 i18n 目录和对应的多语言资源文件。

.NET  i18n 原理、实现一个 i18n 框架的过程详解

在 i18n/Demo5.Lib 目录中创建 en-US.json、zh-CN.json 文件。

.NET  i18n 原理、实现一个 i18n 框架的过程详解

两个文件的内容都设置为:

{  "test": "lib"}

右键修改 en-US.json、zh-CN.json 属性,设置生成操作为内容、始终复制到输出目录。

.NET  i18n 原理、实现一个 i18n 框架的过程详解

然后创建一个 Demo5.Console 项目,引用 Demo5.Lib。

在 i18n/Demo5.Console 目录中创建 en-US.json、zh-CN.json 文件。

.NET  i18n 原理、实现一个 i18n 框架的过程详解

两个文件都设置内容为:

{  "test": "console"}

最后得到的目录结构如下:

├─Demo5.Console│  │  Demo5.Console.csproj│  │  Program.cs│  ││  ├─i18n│  │  └─Demo5.Console│  │          en-US.json│  │          zh-CN.json│├─Demo5.Lib│  │  Demo5.Lib.csproj│  │  Extensions.cs│  ││  ├─i18n│  │  └─Demo5.Lib│  │          en-US.json│  │          zh-CN.json

在 Demo5.Console 的 Program 中使用 IStringLocalizer 来获取 key 在不同语言下的值。

var ioc = new ServiceCollection();
ioc.AddI18n("zh-CN");
ioc.AddI18nResource(options =>{options.ParseDirectory("i18n");});
ioc.AddLib();
var services = ioc.BuildServiceProvider();
// 手动设置当前请求语言
using (var c = new I18nScope("en-US"))
{
    var l1 = services.GetRequiredService>();
    var l2 = services.GetRequiredService>();
    var s1 = l1["test"];
    var s2 = l2["test"];
    Console.WriteLine(s1);
    Console.WriteLine(s2);
}

编译 Demo5.Console ,打开 bin/Debug/net8.0 目录,在 i18n 目录下可以看到如下文件结构:

.
├── Demo5.Console
│   ├── en-US.json
│   └── zh-CN.json
└── Demo5.Lib
    ├── en-US.json
    └── zh-CN.json

Maomi.I18n 的原理其实很简单:每个项目都有自己的多语言文件,编译后所有文件都合并到统一的 i18n 目录里管理,每个子目录名就是项目名,一目了然。使用 IStringLocalizer 时,框架会自动从 T 类型所在的项目名称目录下加载对应的 json 文件。

单个项目管理

上一个例子是每个项目各自管自己的资源文件。那如果整个解决方案共用一套语言文件呢?当然也可以,不需要按目录划分。

直接导入多语言资源文件:

ioc.AddI18nResource(options =>
{
    options.AddJsonFile("zh-CN", "i18n/zh-CN.json");
    options.AddJsonFile("en-US", "i18n/en-US.json");
});

或者自动扫描目录,让 json 文件名自动成为语言名称:

ioc.AddI18nResource(options =>
{
    options.AddJsonDirectory("i18n");
});

使用时直接注入 IStringLocalizer(不需要泛型版本):

// 手动设置当前请求语言
using (var c = new I18nScope("en-US"))
{
    var l1 = services.GetRequiredService();
    var l2 = services.GetRequiredService();
    var s1 = l1["test"];
    var s2 = l2["test"];
    Console.WriteLine(s1);
    Console.WriteLine(s2);
}

如何设置当前语言

设置当前上下文语言,最直接的方式就是改当前线程文化:

CultureInfo.CurrentCulture = new CultureInfo("zh-CN");

另一种方法更灵活——开发者可以自定义如何解析当前程序的多语言上下文,比如从请求头或数据库读取:

public class MyI18nContext : I18nContext
{
    public MyI18nContext()
    {
        base.Culture = ...
    }
    public void Set(CultureInfo cultureInfo)
    {
        base.Culture = cultureInfo;
    }
}
builder.Services.AddScoped();

Web 示例

创建一个 Api 项目,取名 Demo5.Api ,引入 Maomi.I18n.AspNetCore

在项目中新建 i18n/Demo5.Api 目录,然后创建两个 json 文件。

.NET  i18n 原理、实现一个 i18n 框架的过程详解

zh-CN.json 文件内容:

{
  "购物车": {
    "商品名称": "商品名称",
    "加入时间": "加入时间",
    "清理失效商品": "清理失效商品"
  },
  "会员等级": {
    "用户名": "用户名",
    "积分": "积分:{0}",
    "等级": "等级"
  }
}

en-US.json 文件内容:

{
  "购物车": {
    "商品名称": "Product name",
    "加入时间": "Join date",
    "清理失效商品": "Cleaning up failures"
  },
  "会员等级": {
    "用户名": "Username",
    "积分": "Member points:{0}",
    "等级": "Level"
  }
}

Maomi.I18n 框架会扫描程序集目录的 json 文件,解析后以键值对形式存进内存。key 的格式与 IConfiguration 一致,支持嵌套路径(比如 ["购物车:商品名称"]),还支持字符串插值(如 "会员等级:积分"{0} 参数)。

使用 Maomi.I18n 只需要两步:注入 i18n 服务,导入语言资源。

// 添加 i18n 多语言支持
builder.Services.AddI18nAspNetCore(defaultLanguage: "zh-CN");
// 设置多语言来源-json
builder.Services.AddI18nResource(option =>
{
    var basePath = "i18n";
    option.AddJson(basePath);
});

接着添加 i18n 中间件,它会从用户请求中解析出对应的语言。

var app = builder.Build();
app.UseI18n(); // <- 放到中间件靠前的位置

然后添加控制器或直接写中间件测试,注入 IStringLocalizer 即可。

app.UseRouting();
app.Use(async (HttpContext context, RequestDelegate next) =>
{
    var localizer = context.RequestServices.GetRequiredService>();
    await context.Response.WriteAsync(localizer["购物车:商品名称"]);
    return;
});

启动程序,打开地址 http://localhost:5177/test?culture=en-US&ui-culture=en-US,输出就是 Product name

.NET  i18n 原理、实现一个 i18n 框架的过程详解

携带请求语言信息

Maomi.I18n 本质上是基于 ASP.NET Core 的多语言接口进行扩展的,所以它不需要自己费力解析语言,而是充分利用 ASP.NET Core 自带的 RequestLocalizationMiddleware 中间件。这个中间件会自动调用 IRequestCultureProvider 来检索请求所用的语言,我们通过 context.Features.Get() 就能拿到语言信息,大大简化了代码量。

ASP.NET Core 默认提供了三种解析请求语言的方式:

  • URL 路由参数QueryStringRequestCultureProvider),需要携带 cultureui-culture 参数,例如 ?culture=en-US&ui-culture=en-US
  • CookieCookieRequestCultureProvider),cookie 名称为 .AspNetCore.Culture,格式为 c=en-US|uic=en-US
  • 请求头AcceptLanguageHeaderRequestCultureProvider),也是最常用的方式,例如 Accept-Language: zh-CN,zh;q=0.9

开发者可以根据需要修改这三个提供器的参数名,比如改成 lanui

new QueryStringRequestCultureProvider()
{
    QueryStringKey = "lan",
    UIQueryStringKey = "ui"
}

由于 ASP.NET Core 已经帮我们解析好了,我们只需要从 IRequestCultureFeature 中取出语言信息即可:

var requestCultureFeature = context.Features.Get();
var requestCulture = requestCultureFeature?.RequestCulture;

ASP.NET Core 会按顺序依次尝试 QueryStringRequestCultureProviderCookieRequestCultureProviderAcceptLanguageHeaderRequestCultureProvider,一旦某个提供器成功解析出语言,就不再往后执行。如果三个都失败,才会调用自定义的提供器。你也可以调整它们的顺序或自定义实现。

实现一个自定义 IRequestCultureProvider 也很简单,比如要求从 URL 的 cuic 参数中获取语言:

public class I18nRequestCultureProvider : IRequestCultureProvider
{
    private readonly string _defaultLanguage;
    public I18nRequestCultureProvider(string defaultLanguage)
    {
        _defaultLanguage = defaultLanguage;
    }
    private const string RouteValueKey = "c";
    private const string UIRouteValueKey = "uic";

    public override Task DetermineProviderCultureResult(HttpContext httpContext)
    {
        var request = httpContext.Request;
        if (!request.RouteValues.Any())
        {
            return NullProviderCultureResult;
        }
        string? queryCulture = null;
        string? queryUICulture = null;
        if (!string.IsNullOrWhiteSpace(RouteValueKey))
        {
            queryCulture = request.RouteValues[RouteValueKey]?.ToString();
        }
        // 其他过程省略
        var providerResultCulture = new ProviderCultureResult(queryCulture, queryUICulture);
        return Task.FromResult(providerResultCulture);
    }
}

需要注意的是,IRequestCultureProvider 不能通过容器注入,而是在 RequestLocalizationOptions 中配置:

services.Configure(options =>
{
    options.RequestCultureProviders.Add(new I18nRequestCultureProvider(defaultLanguage));
});

想调整提供器的顺序,直接操作 options.RequestCultureProviders 集合即可。

实现 i18n 框架

聊完了用法,接下来我们亲手搭建一个 i18n 框架。全部代码结构如下:

.NET  i18n 原理、实现一个 i18n 框架的过程详解

文件说明:

// 当前程序多语言上下文
I18nContext.cs
// 多语言资源接口定义
I18nResource.cs
// i18n 语言资源工厂
I18nResourceFactory.cs
// 设置当前语言作用域
I18nScope.cs
// 服务注入扩展
I18nExtensions.cs
// 从 json 文件读取多语言资源扩展
JsonResourceExtensions.cs
// 实现 I18nResourceFactory
InternalI18nResourceFactory.cs
// 自定义请求语言解析
I18nRequestCultureProvider.cs
// 实现 IStringLocalizer 接口
I18nStringLocalizer.cs
// 实现 IStringLocalizer 接口
I18nStringLocalizer`.cs
// 实现 I18nResource,通过 json 文件导入语言资源
JsonResource.cs
// 解析 json 的帮助类
ReadJsonHelper.cs

抽象接口

设计多语言框架,首先要划分三个角色:使用者框架自身多语言提供者。使用者通过抽象接口获取 key 对应的值,提供者通过抽象接口提供键值对数据,框架本身则是桥梁。

我们不需要关心多语言数据存在哪里——可以是 json 文件、嵌入程序集、Redis,甚至数据库。统一通过接口加载即可。

先定义 I18nResource 接口:

/// 
/// i18n 语言资源.
/// 
/// 每个 I18nResource 对应一种语言的一个资源文件.
public interface I18nResource
{
    CultureInfo SupportedCulture { get; }
    LocalizedString Get(string culture, string name);
    LocalizedString Get(string culture, string name, params object[] arguments);
    IEnumerable GetAllStrings(bool includeParentCultures);
}

public interface I18nResource : I18nResource { }

然后是多语言资源工厂,管理所有 I18nResource 实例,支持从容器中取出资源:

public interface I18nResourceFactory
{
    IList SupportedCultures { get; }
    IList Resources { get; }
    IList ServiceResources { get; }
    I18nResourceFactory AddServiceType(Type resourceType);
    I18nResourceFactory Add(I18nResource resource);
    I18nResourceFactory Add(I18nResource resource);
}

使用者接口方面,ASP.NET Core 已经定义了 IStringLocalizerIStringLocalizer,我们直接实现它们即可。另外定义一个 I18nContext 来存储当前请求的语言信息,下游服务通过它获取当前语言:

public class I18nContext
{
    public CultureInfo Culture { get; internal set; } = CultureInfo.CurrentCulture;
}

接下来是实现 I18nStringLocalizerI18nStringLocalizer 的核心代码。这两个类会遍历 I18nResourceFactory 中的所有资源,根据当前语言查找 key 对应的值。如果找不到,就返回 key 本身作为默认值。(具体代码较长,原文中已完整给出,此处不再重复粘贴,但确保保留在原位。)

I18nScope 的作用是临时修改 CultureInfo.CurrentCulture,方便在控制台或测试中手动切换语言:

public class I18nScope : IDisposable
{
    private readonly CultureInfo _defaultCultureInfo;
    public I18nScope(string language)
    {
        _defaultCultureInfo = CultureInfo.CurrentCulture;
        CultureInfo.CurrentCulture = CultureInfo.CreateSpecificCulture(language);
    }
    public void Dispose()
    {
        CultureInfo.CurrentCulture = _defaultCultureInfo;
    }
}

实现从 json 读取语言资源

Maomi.I18n 自带了一个从 json 文件读取多语言的 DictionaryResource 实现。核心思路:每个项目可以创建 i18n 目录,下面再以项目名建子目录,子目录里放语言文件。

这样做的好处是:编译时主项目的 i18n 目录会收集所有依赖项目中的语言文件,且不会冲突。打包成 nuget 时,这些文件也会被打进去,其他开发者引用 nuget 包后直接就能用。

DictionaryResource 实现了 I18nResource,内部用一个字典存储键值对。其泛型版本 DictionaryResource 会自动与 T 类型的程序集绑定,避免跨程序集混淆。

另外提供了扩展方法 JsonResourceExtensions,支持扫描目录、添加单个 json 文件等操作,细节都在原代码中,这里不再展开。

管理 I18nResourceFactory 的核心实现 InternalI18nResourceFactory 也很简单,维护三个列表:支持的语言、资源实例、服务类型。

最后通过 I18nExtensions 把服务注入容器,包括 IStringLocalizerFactoryIStringLocalizer 等。对于 ASP.NET Core 应用,还有额外的 AddI18nAspNetCoreUseI18n 中间件扩展。

针对模型验证的多语言,还提供了 AddI18nDataAnnotation 扩展,让验证错误信息也能跟随语言切换。

单元测试

写框架不写单元测试,就像盖房子不打地基。我们用 xUnit 配合 Microsoft.AspNetCore.Mvc.Testing 来验证 i18n 框架的正确性。

项目结构如下:

.NET  i18n 原理、实现一个 i18n 框架的过程详解

先构建一个测试用的 Web Host:

using var host = await new HostBuilder()
    .ConfigureWebHost(webBuilder =>
    {
        webBuilder.UseTestServer()
            .ConfigureServices(services =>
            {
                services.AddControllers();
                services.AddI18n(defaultLanguage: "zh-CN");
                services.AddI18nResource(option =>
                {
                    var basePath = "i18n";
                    option.AddJson(basePath);
                });
            })
            .Configure(app =>
            {
                app.UseI18n();
                app.UseRouting();
                app.Use(async (HttpContext context, RequestDelegate next) =>
                {
                    var localizer = context.RequestServices.GetRequiredService>();
                    await context.Response.WriteAsync(localizer["购物车:商品名称"]);
                    return;
                });
            });
    })
    .StartAsync();

通过 host.GetTestClient() 拿到 HttpClient,然后分别测试 URL 参数CookieAccept-Language 头 三种方式:

var httpClient = host.GetTestClient();

// 1. 路由参数
var response = await httpClient.GetStringAsync("/test?culture=en-US&ui-culture=en-US");
Assert.Equal("Product name", response);

response = await httpClient.GetStringAsync("/test?culture=zh-CN&ui-culture=zh-CN");
Assert.Equal("商品名称", response);

// 2. Cookie
httpClient.DefaultRequestHeaders.Add("Cookie", ".AspNetCore.Culture=c=en-US|uic=en-US");
response = await httpClient.GetStringAsync("/test");
Assert.Equal("Product name", response);

httpClient.DefaultRequestHeaders.Remove("Cookie");
httpClient.DefaultRequestHeaders.Add("Cookie", ".AspNetCore.Culture=c=zh-CN|uic=zh-CN");
response = await httpClient.GetStringAsync("/test");
Assert.Equal("商品名称", response);

// 3. Accept-Language 头
httpClient.DefaultRequestHeaders.Remove("Cookie");
httpClient.DefaultRequestHeaders.AcceptLanguage.Clear();
httpClient.DefaultRequestHeaders.AcceptLanguage.Add(new StringWithQualityHeaderValue("zh-CN"));
response = await httpClient.GetStringAsync("/test");
Assert.Equal("商品名称", response);

httpClient.DefaultRequestHeaders.AcceptLanguage.Clear();
httpClient.DefaultRequestHeaders.AcceptLanguage.Add(new StringWithQualityHeaderValue("en-US"));
response = await httpClient.GetStringAsync("/test");
Assert.Equal("Product name", response);

基于 Redis 的动态多语言

有些场景下,多语言内容需要动态更新,比如运营后台实时修改翻译,不希望重启服务。这时可以用 Redis 来存储语言数据。

Maomi.I18n.Redis 扩展库实现了从 Redis 加载多语言数据,并利用 FreeRedis 的客户端缓存(Client-Side Caching)将数据拉到本地内存,实现“实时更新 + 高性能”的效果。

public class RedisI18nResource : I18nResource
{
    private readonly RedisClient _redisClient;
    private readonly string _pathPrefix;

    internal RedisI18nResource(RedisClient redisClient, string pathPrefix, TimeSpan expired, int capacity = 10)
    {
        _redisClient = redisClient;
        _pathPrefix = pathPrefix;
        // Redis client-side 模式
        redisClient.UseClientSideCaching(new ClientSideCachingOptions
        {
            Capacity = capacity,
            KeyFilter = key => key.StartsWith(pathPrefix),
            CheckExpired = (key, dt) => DateTime.Now.Subtract(dt) > expired
        });
        // 首次加载
        GetAllStrings(default);
    }
    // ... 实现 Get、GetAllStrings 等方法,从 Redis Hash 读取
}

扩展方法使用示例:

WRedisClient cli = new RedisClient("127.0.0.1:6379,defaultDatabase=0");
builder.Services.AddI18n(defaultLanguage: "zh-CN");
builder.Services.AddI18nResource(option =>
{
    option.AddRedis(cli, "language", TimeSpan.FromMinutes(100), 10);
    option.AddJson("i18n");
});

在 Redis 中创建一个 Hash 类型的 key(例如 language:zh-CN),往里添加键值对,客户端就能直接读到最新数据。

nuget 打包嵌入 json

企业内部开发时,经常把公共类库打成 nuget 包供其他团队使用。多语言资源文件也要一起打包。

以 Demo5.Nuget 项目为例,目录结构如下:

.NET  i18n 原理、实现一个 i18n 框架的过程详解

修改 .csproj 文件,将 json 文件作为 Content 并设置 Pack="true",指定 PackageCopyToOutputPackagePath


  
    true
    Always
    contentFiles\any\any\i18n\Demo5.Nuget\en-US.json
  
  
    true
    Always
    contentFiles\any\any\i18n\Demo5.Nuget\zh-CN.json
  

对于 Web 项目,编译器默认会给 .json 文件设置 属性,所以需要先关闭 EnableDefaultContentItems 避免冲突:

false

其他开发者引入这个 nuget 包后,项目中就会自动出现对应的语言文件。

本文内容来源于互联网,如有侵权请联系删除。
作者最新文章
编程开发
相关文章 更多
C++动态数组初始化怎么写?常用语句与代码示例
C++动态数组初始化怎么写?常用语句与代码示例

深入解析C++中动态数组的初始化机制,涵盖new操作符的不同用法、基本类型与类对象的初始化差异,以及为何在现代C++开发中应优先使用std::vector。

圆通速递查单号官网
圆通速递查单号官网

圆通速递查单号官网在哪里? 不少朋友都在寻找圆通快递的官方物流查询入口。别急,这就为你揭晓答案,并带你详细了解它的核心功能与服务。 圆通速递的官方网站地址是:https://www.yto.net.cn/。记住这个地址,所有官方服务都从这里开始。 官网核心功能 来到官网,你会发现它的运单查询服务是全

在小说搜搜找不到想看的小说怎么办?小说搜搜换源功能使用详解【必学】
在小说搜搜找不到想看的小说怎么办?小说搜搜换源功能使用详解【必学】

小说搜搜搜索不到结果?五种实用解决方法帮你搞定 在小说搜搜里搜不到想看的书?这事儿其实挺常见。问题多半出在书源上——要么是默认的书源还没来得及收录,要么是原先的源数据失效了,更新没跟上。别急,下面这五条解决路径,基本能覆盖绝大多数情况,操作起来也不复杂。 一、通过阅读页调出换源入口手动切换 这个方法

来看小说网最新章节免费阅读网
来看小说网最新章节免费阅读网

来看小说网最新章节免费阅读网-来看小说网全网小说同步更新入口 不少资深书友都在问,来看小说网的全网小说同步更新入口究竟在哪?别急,答案就在这里。接下来,就为大家详细揭开这个平台的神秘面纱,看看它究竟提供了怎样的阅读体验。 来看小说网的官方入口是:https://www.kanxiaoshuo.net

using namespace 使用中遇到的问题怎么解决
using namespace 使用中遇到的问题怎么解决

命名空间的基本概念与常见引入问题在C++等编程语言中,命名空间(namespace)是一种将代码标识符(如变量、函数、类名)封装在特定名称下的机制,其主要目的是避免命名冲突,尤其是在大型项目或使用多个第三方库时。使用“using namespace”指令可以将指定命名空间中的所有名称引入当前作用域,

c语言函数递归 实操经验总结:这些技巧很实用
c语言函数递归 实操经验总结:这些技巧很实用

理解递归的基本原理在C语言中,递归是一种函数调用自身的编程技术。要掌握它,首先需要理解其核心思想:将一个复杂的大问题,分解为一个或几个与原问题相似但规模更小的子问题,直到子问题足够简单,可以直接求解。这个过程通常包含两个关键部分:递归出口和递归体。递归出口定义了问题何时不再继续分解,即最简单、可直接

c语言函数递归 怎么选?常见方案对比分析
c语言函数递归 怎么选?常见方案对比分析

递归函数的基本概念与适用场景在C语言编程中,递归是一种函数调用自身的编程技巧。它并非适用于所有问题,但在处理某些具有自相似结构的问题时,能提供极其清晰和优雅的解决方案。递归的核心思想是将一个大规模问题分解为一个或多个同类型但规模更小的子问题,直到子问题简单到可以直接求解。典型的适用场景包括树形结构的

Objective-C 内存管理入门:从 alloc 到 dealloc 的生命周期详解
Objective-C 内存管理入门:从 alloc 到 dealloc 的生命周期详解

理解内存管理的基石在Objective-C的编程世界中,内存管理是开发者必须掌握的核心技能之一。它直接关系到应用的性能、稳定性与资源利用效率。与一些采用自动垃圾回收机制的语言不同,Objective-C在很长一段时间里,依赖一套基于引用计数的、需要开发者部分介入的管理规则。这套规则的核心思想是明确的

如何正确使用 dealloc 以避免 iOS 应用中的内存泄漏
如何正确使用 dealloc 以避免 iOS 应用中的内存泄漏

理解 dealloc 的角色与时机在 iOS 应用开发中,内存管理是保障应用性能与稳定性的基石。dealloc 方法是 Objective-C 中对象生命周期结束时的关键回调,它标志着对象即将被系统回收内存。正确理解其触发时机至关重要:当一个对象的引用计数降为零时,运行时系统会自动调用该对象的 de

深入理解 Objective-C 中的 dealloc 方法:内存管理核心机制
深入理解 Objective-C 中的 dealloc 方法:内存管理核心机制

内存管理的基石在Objective-C的世界里,内存管理是开发者必须掌握的核心技能之一。作为一门在手动引用计数(MRC)时代诞生的语言,Objective-C要求程序员对对象的生命周期有清晰的认识。dealloc方法正是这一生命周期中至关重要的终点站。它是一个实例方法,当对象的引用计数降为零时,系统

查看更多
精品专题 更多
装机必备
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows
Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

macOS软件
macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

Mac软件 更多
灵活计算器
灵活计算器
macOS/iOS/Android

灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

赤友清理大师
赤友清理大师
macOS

赤友清理大师是一款为 Mac 设计的智能清理优化工具,可精准扫描垃圾、大文件、重复文件等,释放磁盘空间。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

WINDOWS 更多
Windows 10
Windows 10
Windows

Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

密码键盘
密码键盘
Windows/macOS/iOS/Android

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。