1.Swift之Codable实战技巧
2.å¦ä½ä½¿ç¨Multipeer Connectivity
3.iOSä¸copyï¼strongï¼retainï¼weakåassignçåºå«
Swift之Codable实战技巧
作者 | kingnight
Part.1 引言
本文将深入探讨Swift4.0引入的Codable新特性,它能将程序内部的数据结构序列化为可交换数据,亦能将通用数据格式反序列化为内部使用的数据结构,显著提升了对象与表示间转换的体验。以狐友iOS团队的实战经验为依据,本文将详细解析Codable使用过程中的左左网源码常见问题与解决方案。
Part.2 简介
Codable协议自Swift4.0起被引入,旨在取代NSCoding协议,支持结构体、枚举及类,并能将JSON等弱类型数据转换为代码中的强类型数据。Codable由Decodable与Encodable两个协议组成,分别定义了初始化与编码方法。Swift标准库中的多种类型如String、Int、Double及Foundation框架下的Data、Date、测评系统网站源码URL等,已默认支持Codable协议,仅需声明协议即可。
以学生信息为例,通过声明支持Codable协议,学生信息对象就能默认支持init(from:)与encode(to:)方法,无需额外编写代码。本文将重点介绍使用JSON格式进行编码与解码的深度优先搜索源码过程。
Part.3 应用场景
JSON格式广泛应用于网络数据传输,Codable协议能够将JSON数据转换为应用程序内部使用的格式,取代繁琐的手动解码过程,大幅减少编码与解码的重复工作。
此外,Codable协议替代NSCoding协议,使得遵循Codable协议的对象能够无缝集成NSKeyedArchiver与NSKeyedUnarchiver进行数据持久化与反持久化操作,简化了原有流程,数据精灵apt源码显著提升了效率。
Part.4 使用技巧
4.1 嵌套对象、数组与字典
Swift4支持条件一致性规则,当数组中的每个元素与字典中的键值均遵循Codable协议,整体对象即可默认遵循Codable协议。
以班级对象为例,通过一致性的规则,即可实现对复杂数据结构的源码 下载 排课系统解码工作。
4.2 空对象或空值处理
在复杂业务场景下,数据结构可能包含空对象或空值,Codable提供灵活的处理方式。通过将对象属性设置为可选类型,Codable能够自动将空对象映射为nil,简化了处理逻辑。
通过调整源对象属性类型为可选值,能够有效解决空对象或空值的解析问题。
4.3 字段匹配与键值转换
JSON中使用蛇形命名法(snake_case)命名键值,而Swift API设计中倾向于UpperCamelCase与lowerCamelCase。通过JSONDecoder的keyDecodingStrategy属性,可方便地在不同命名规范之间转换。
对于键值不匹配的情况,可通过CodingKeys自定义映射规则,指定明确的字符串原始值,以确保正确解析。
4.4 定制日期格式处理
日期格式是数据处理中常见的需求,Codable提供灵活的日期解码机制。通过dateDecodingStrategy属性,可针对不同日期标准如ISO与RFC进行自定义解析。
4.5 枚举值转换
在移动应用开发中,模版类型字段常用于区别展示样式。通过实现字符串或整型数据到枚举类型的转换,可以简化代码逻辑并提升用户体验。
4.6 动态键值结构处理
当Web服务下发动态数据结构时,Codable提供灵活的init与encode方法,支持处理动态键值问题,简化了代码实现。
4.7 特殊类型处理
对于不遵循Codable协议的特殊类型,通过重写编码与初始化方法,可以实现与Codable协议的兼容性,避免潜在冲突。
Part.5 总结
引入Codable协议,简化了Swift程序中数据结构之间的转换过程,显著提升了开发效率。本文通过多种场景与实例解析了Codable的使用技巧与常见问题解决方法,希望对读者在实际开发中提供参考与启示。
å¦ä½ä½¿ç¨Multipeer Connectivity
æ¬æç±éåæ[å客]ç¿»è¯èªnshipsterä¸çMultipeer Connectivityä¸èã Multipeer connectivityæ¯ä¸ä¸ªä½¿éè¿è®¾å¤éè¿Wi-Fiç½ç»ãP2P Wi-Fi以åèç个人å±åç½è¿è¡éä¿¡çæ¡æ¶ãäºç¸é¾æ¥çèç¹å¯ä»¥å®å ¨å°ä¼ éä¿¡æ¯ãæµææ¯å ¶ä»æ件èµæºï¼èä¸ç¨éè¿ç½ç»æå¡ã
Advertising & Discovering
éä¿¡ç第ä¸æ¥æ¯è®©å¤§å®¶äºç¸ç¥éå½¼æ¤ï¼æ们éè¿å¹¿æ(Advertising)ååç°(discovering)æå¡æ¥å®ç°ã
广æä½ä¸ºæå¡å¨æç´¢éè¿çèç¹ï¼èèç¹åæ¶ä¹å»æç´¢éè¿ç广æãå¨è®¸å¤æ åµä¸ï¼å®¢æ·ç«¯åæ¶å¹¿æ并åç°åä¸ä¸ªæå¡ï¼è¿å°å¯¼è´ä¸äºæ··ä¹±ï¼å°¤å ¶æ¯å¨client-server模å¼ä¸ã
æ以ï¼æ¯ä¸ä¸ªæå¡é½åºæä¸ä¸ªç±»åï¼æ 示符ï¼ï¼å®æ¯ç±ASCIIåæ¯ãæ°ååâ-âç»æççææ¬ä¸²ï¼æå¤ä¸ªå符ãé常ï¼ä¸ä¸ªæå¡çåååºè¯¥ç±åºç¨ç¨åºçååå¼å§ï¼åè¾¹è·â-âåä¸ä¸ªç¬ç¹çæ述符å·ã(ä½è 认为è¿å com.apple.*æ 示符å¾å)ï¼å°±åä¸è¾¹ï¼
static NSString * const XXServiceType = @"xx-service";
ä¸ä¸ªèç¹æä¸ä¸ªå¯ä¸æ 示MCPeerID对象ï¼ä½¿ç¨å±ç¤ºå称è¿è¡åå§åï¼å®å¯è½æ¯ç¨æ·æå®çæµç§°ï¼ææ¯å纯ç设å¤å称ã
MCPeerID *localPeerID = [[MCPeerID alloc] initWithDisplayName:[[UIDevice currentDevice] name]];
èç¹ä½¿ç¨NSNetServiceæè Bonjour C APIè¿è¡æå¨å¹¿æååç°ï¼ä½è¿æ¯ä¸ä¸ªç¹å«æ·±å ¥çé®é¢ï¼å ³äºæå¨èç¹ç®¡çå¯å ·ä½åè§MCSessionææ¡£ã
Advertising
æå¡ç广æéè¿MCNearbyServiceAdvertiseræ¥æä½ï¼åå§åæ¶å¸¦çæ¬å°èç¹ãæå¡ç±»å以åä»»ä½å¯ä¸åç°è¯¥æå¡çèç¹è¿è¡éä¿¡çå¯éä¿¡æ¯ã
åç°ä¿¡æ¯ä½¿ç¨Bonjour TXT records encodedï¼according to RFC ï¼åéã
MCNearbyServiceAdvertiser *advertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:localPeerID discoveryInfo:nil serviceType:XXServiceType]; advertiser.delegate = self; [advertiser startAdvertisingPeer];
ç¸å ³äºä»¶ç±advertiserç代çæ¥å¤çï¼ééµä»MCNearbyServiceAdvertiserDelegateåè®®ã
å¨ä¸ä¾ä¸ï¼èèå°ç¨æ·å¯ä»¥éæ©æ¯å¦æ¥åææç»ä¼ å ¥è¿æ¥è¯·æ±ï¼å¹¶ææ以æç»æå±è½ä»»ä½æ¥èªè¯¥èç¹çåç»è¯·æ±é项ã
#pragma mark - MCNearbyServiceAdvertiserDelegate - (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void(^)(BOOL accept, MCSession *session))invitationHandler { if ([self.mutableBlockedPeers containsObject:peerID]) { invitationHandler(NO, nil); return; } [[UIActionSheet actionSheetWithTitle:[NSString stringWithFormat:NSLocalizedString(@"Received Invitation from %@", @"Received Invitation from { Peer}"), peerID.displayName] cancelButtonTitle:NSLocalizedString(@"Reject", nil) destructiveButtonTitle:NSLocalizedString(@"Block", nil) otherButtonTitles:@[NSLocalizedString(@"Accept", nil)] block:^(UIActionSheet *actionSheet, NSInteger buttonIndex) { BOOL acceptedInvitation = (buttonIndex == [actionSheet firstOtherButtonIndex]); if (buttonIndex == [actionSheet destructiveButtonIndex]) { [self.mutableBlockedPeers addObject:peerID]; } MCSession *session = [[MCSession alloc] initWithPeer:localPeerID securityIdentity:nil encryptionPreference:MCEncryptionNone]; session.delegate = self; invitationHandler(acceptedInvitation, (acceptedInvitation ? session : nil)); }] showInView:self.view]; }
为äºç®åèµ·è§ï¼æ¬ä¾ä¸ä½¿ç¨äºä¸ä¸ªå¸¦æblockçactionsheetæ¥ä½ä¸ºæä½æ¡ï¼å®å¯ä»¥ç´æ¥ç»invitationHandlerä¼ éä¿¡æ¯ï¼ç¨ä»¥é¿å å建å管çdelegateé æçè¿äºåä¹±çä¸å¡é»è¾ï¼ä»¥é¿å å建å管çèªå®ä¹delegate objecté æçè¿äºåä¹±çä¸å¡é»è¾ãè¿ç§æ¹æ³å¯ä»¥ç¨categoryæ¥å®ç°ï¼æè æ¹ç¼ä»»ä½ä¸ä¸ªCocoaPodséææçå®ç°ã
Creating a Session
å¨ä¸é¢çä¾åä¸ï¼æ们å建äºsessionï¼å¹¶å¨æ¥åé请è¿æ¥æ¶ä¼ éå°èç¹ãä¸ä¸ªMCSession对象è·æ¬å°èç¹æ è¯ç¬¦ãsecurityIdentity以åencryptionPreferenceåæ°ä¸èµ·è¿è¡åå§åã
MCSession *session = [[MCSession alloc] initWithPeer:localPeerID securityIdentity:nil encryptionPreference:MCEncryptionNone]; session.delegate = self;
securityIdentityæ¯ä¸ä¸ªå¯éåæ°ãéè¿X.è¯ä¹¦ï¼å®å 许èç¹å®å ¨è¯å«å¹¶è¿æ¥å ¶ä»èç¹ãå½è®¾ç½®äºè¯¥åæ°æ¶,第ä¸ä¸ªå¯¹è±¡åºè¯¥æ¯è¯å«å®¢æ·ç«¯çSecIdentityRefï¼æ¥çæ¯ä¸ä¸ªææ´å¤ä¸ªç¨ä»¥æ ¸å®æ¬å°èç¹èº«ä»½çSecCertificateRef objectsã
encryptionPreferenceåæ°æå®æ¯å¦å å¯èç¹ä¹é´çéä¿¡ãMCEncryptionPreferenceæ举æä¾çä¸ç§å¼æ¯:
MCEncryptionOptional:ä¼è¯æ´å欢使ç¨å å¯,ä½ä¼æ¥åæªå å¯çè¿æ¥ã
MCEncryptionRequired:ä¼è¯éè¦å å¯ã
MCEncryptionNone:ä¼è¯ä¸åºè¯¥å å¯ã
å¯ç¨å å¯ä¼æ¾èéä½ä¼ è¾éçï¼æ以é¤éä½ çåºç¨ç¨åºå¾ç¹å«ï¼éè¦å¯¹ç¨æ·ææä¿¡æ¯çå¤çï¼å¦å建议使ç¨MCEncryptionNoneã
MCSessionDelegateåè®®å°ä¼å¨åéåæ¥åä¿¡æ¯çé¨å被è¦ç.
Discovering
客æ·ç«¯ä½¿ç¨MCNearbyServiceBrowseræ¥åç°å¹¿æï¼å®éè¦local peeræ è¯ç¬¦ï¼ä»¥åé常类似MCNearbyServiceAdvertiserçæå¡ç±»åæ¥åå§åï¼
MCNearbyServiceBrowser *browser = [[MCNearbyServiceBrowser alloc] initWithPeer:localPeerID serviceType:XXServiceType]; browser.delegate = self;
å¯è½ä¼æå¾å¤èç¹å¹¿æä¸ä¸ªç¹å®çæå¡ï¼æ以为äºæ¹ä¾¿ç¨æ·ï¼æå¼åè ï¼ï¼MCBrowserViewControllerå°æä¾ä¸ä¸ªå ç½®çãæ åçæ¹å¼æ¥åç°é¾æ¥å°å¹¿æèç¹ï¼
MCBrowserViewController *browserViewController = [[MCBrowserViewController alloc] initWithBrowser:browser session:session]; browserViewController.delegate = self; [self presentViewController:browserViewController animated:YES completion: ^{ [browser startBrowsingForPeers]; }];
å½browserå®æèç¹è¿æ¥åï¼å®å°ä½¿ç¨å®çdelegateè°ç¨browserViewControllerDidFinish:ï¼ä»¥éç¥å±ç¤ºè§å¾æ§å¶å¨--å®åºè¯¥æ´æ°UI以éåºæ°è¿æ¥ç客æ·ç«¯ã
Sending & Receiving Information
ä¸æ¦èç¹å½¼æ¤ç¸è¿ï¼å®ä»¬å°è½äºä¼ ä¿¡æ¯ãMultipeer Connectivityæ¡æ¶åºåä¸ç§ä¸åå½¢å¼çæ°æ®ä¼ è¾ï¼
Messagesæ¯å®ä¹æç¡®çä¿¡æ¯ï¼æ¯å¦ç«¯ææ¬æè å°åºåå对象ã
Streams æµæ¯å¯è¿ç»ä¼ è¾æ°æ®ï¼å¦é³é¢ï¼è§é¢æå®æ¶ä¼ æå¨äºä»¶ï¼çä¿¡æ¯å ¬å¼æ¸ éã
Resourcesæ¯å¾çãçµå½±ä»¥åææ¡£çæ件ã
Messages
Messages使ç¨-sendData:toPeers:withMode:error::æ¹æ³åéã
NSString *message = @"Hello, World!"; NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding]; NSError *error = nil; if (![self.session sendData:data toPeers:peers withMode:MCSessionSendDataReliable error:&error]) { NSLog(@"[Error] %@", error); }
éè¿MCSessionDelegateæ¹æ³ -sessionDidReceiveData:fromPeer:æ¶åä¿¡æ¯ã以ä¸æ¯å¦ä½è§£ç å å示ä¾ä»£ç ä¸åéçæ¶æ¯ï¼
#pragma mark - MCSessionDelegate - (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID { NSString *message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"%@", message); }
å¦ä¸ç§æ¹æ³æ¯åéNSKeyedArchiverç¼ç ç对象ï¼
id <NSSecureCoding> object = // ...; NSData *data = [NSKeyedArchiver archivedDataWithRootObject:object]; NSError *error = nil; if (![self.session sendData:data toPeers:peers withMode:MCSessionSendDataReliable error:&error]) { NSLog(@"[Error] %@", error); } #pragma mark - MCSessionDelegate - (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID { NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; unarchiver.requiresSecureCoding = YES; id object = [unarchiver decodeObject]; [unarchiver finishDecoding]; NSLog(@"%@", object); }
为äºé²è对象æ¿æ¢æ»å»,设置requiresSecureCoding为YESæ¯å¾éè¦çï¼è¿æ ·å¦ææ ¹å¯¹è±¡ç±»æ²¡æéµä»<NSSecureCoding>ï¼å°±ä¼æåºä¸ä¸ªå¼å¸¸ã欲äºè§£æ´å¤ä¿¡æ¯ï¼è¯·åé [NSHipster article on NSSecureCoding]ã
Streams
Streams ä½¿ç¨ -startStreamWithName:toPeer:å建ï¼
NSOutputStream *outputStream = [session startStreamWithName:name toPeer:peer]; stream.delegate = self; [stream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; [stream open]; // ...
Streamséè¿MCSessionDelegateçæ¹æ³session:didReceiveStream:withName:fromPeer:æ¥æ¥æ¶ï¼
#pragma mark - MCSessionDelegate - (void)session:(MCSession *)session didReceiveStream:(NSInputStream *)stream withName:(NSString *)streamName fromPeer:(MCPeerID *)peerID { stream.delegate = self; [stream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; [stream open]; }
è¾å ¥åè¾åºçstreamså¿ é¡»å®æ好并æå¼ï¼ç¶åæè½ä½¿ç¨å®ä»¬ãä¸æ¦è¿æ ·åï¼streamså°±å¯ä»¥è¢«è¯»åºååå ¥ã
Resources
Resources åéä½¿ç¨ -sendResourceAtURL:withName:toPeer:withCompletionHandler::
NSURL *fileURL = [NSURL fileURLWithPath:@"path/to/resource"]; NSProgress *progress = [self.session sendResourceAtURL:fileURL withName:[fileURL lastPathComponent] toPeer:peer withCompletionHandler:^(NSError *error) { NSLog(@"[Error] %@", error); }];
è¿åçNSProgress对象å¯ä»¥æ¯éè¿KVO(Key-Value Observed)æ¥çè§æä»¶ä¼ è¾çè¿åº¦ï¼å¹¶ä¸å®æä¾åæ¶ä¼ è¾çæ¹æ³ï¼-cancelã
æ¥æ¶èµæºå®ç°MCSessionDelegate两ç§æ¹æ³ï¼-session:didStartReceivingResourceWithName:fromPeer:withProgress: å -session:didFinishReceivingResourceWithName:fromPeer:atURL:withError:
#pragma mark - MCSessionDelegate - (void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progress { // ... } - (void)session:(MCSession *)session didFinishReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID atURL:(NSURL *)localURL withError:(NSError *)error { NSURL *destinationURL = [NSURL fileURLWithPath:@"/path/to/destination"]; NSError *error = nil; if (![[NSFileManager defaultManager] moveItemAtURL:localURL toURL:destinationURL error:&error]) { NSLog(@"[Error] %@", error); } }
å次说æï¼å¨ä¼ è¾æé´NSProgress parameter in -session:didStartReceivingResourceWithName:fromPeer:withProgress:å 许æ¥æ¶èç¹æ¥çæ§æä»¶ä¼ è¾è¿åº¦ãå¨-session:didFinishReceivingResourceWithName:fromPeer:atURL:withError:ä¸,delegateç责任æ¯ä»ä¸´æ¶localURL移å¨æ件è³æ°¸ä¹ ä½ç½®ã
Multipeeræ¯çªç ´æ§çAPIï¼å ¶ä»·å¼æååå¼å§è¢«ç解ãè½ç¶å®æ´çæ¯æåè½æ¯å¦AirDropç®åä» éäºææ°ç设å¤ï¼ä½ åºè¯¥ä¼çå°å®å°æ为让ææ人ç¼æçåè½ã
iOSä¸copyï¼strongï¼retainï¼weakåassignçåºå«
ããcopyä¸retainçåºå«ï¼
ããcopyæ¯å建ä¸ä¸ªæ°å¯¹è±¡ï¼retainæ¯å建ä¸ä¸ªæéï¼å¼ç¨å¯¹è±¡è®¡æ°å 1ãCopyå±æ§è¡¨ç¤ºä¸¤ä¸ªå¯¹è±¡å 容ç¸åï¼æ°ç对象retain为1 ï¼ä¸æ§æ对象çå¼ç¨è®¡æ°æ å ³ï¼æ§æ对象没æååãcopyåå°å¯¹è±¡å¯¹ä¸ä¸æçä¾èµã
ããretainå±æ§è¡¨ç¤ºä¸¤ä¸ªå¯¹è±¡å°åç¸åï¼å»ºç«ä¸ä¸ªæéï¼æéæ·è´ï¼ï¼å 容å½ç¶ç¸åï¼è¿ä¸ªå¯¹è±¡çretainå¼+1ä¹å°±æ¯è¯´ï¼retain æ¯æéæ·è´ï¼copy æ¯å 容æ·è´ã
ãã
ããå½ç¶å¨iosä¸å¹¶ä¸æ¯ææç对象é½æ¯æcopyï¼mutableCopyï¼éµå®NSCopying åè®®çç±»å¯ä»¥åécopyæ¶æ¯ï¼éµå®NSMutableCopying åè®®çç±»æå¯ä»¥åémutableCopyæ¶æ¯ãåå¦åéäºä¸ä¸ªæ²¡æéµå®ä¸è¯ä¸¤åè®®èåé copyæè mutableCopy,é£ä¹å°±ä¼åçå¼å¸¸ãä½æ¯é»è®¤çios类并没æéµå®è¿ä¸¤ä¸ªåè®®ãå¦ææ³èªå®ä¹ä¸ä¸copy é£ä¹å°±å¿ é¡»éµå®NSCopying,并ä¸å®ç° copyWithZone: æ¹æ³ï¼å¦ææ³èªå®ä¹ä¸ä¸mutableCopy é£ä¹å°±å¿ é¡»éµå®NSMutableCopying,并ä¸å®ç° mutableCopyWithZone: æ¹æ³ã
ããé¦å æ们éè¦æè¿æ ·çä¸ä¸ªåæï¼
ããï¼»array addObject:obj];
ããè¿æ ·objçå¼ç¨è®¡æ°ä¼å¢å 1ï¼å¦æ使ç¨removeåobjçå¼ç¨è®¡æ°ä¼åä¸ã
ããios对éåçå åå¤çå°±æ¯è¿æ ·çã
ããé£ä¹ï¼å设objåªè¢«arrayæ¥æï¼
ããid temp ï¼ [array objectAtIndex:0];
ãã[array removeObjectAtIndex:0];
ããå¦æä½ åè¦ä½¿ç¨tempå°±ä¼åºéï¼å 为è¿ä¸ªæ¶åobjå·²ç»è¢«éæ¾äºã
ããï¼æéä¸ä¸ï¼å¦æç¨NSStringåæµè¯ï¼è¦æ³¨æ@âabcâæ¯å¸¸é :-) ï¼
ããç±äºå¨ç¨åºä¸ç»å¸¸ä¼éå°éåç±»çä¼ å¼ï¼æ以ï¼ç®åçretainæªå¿ å¤ç¨ï¼éè¦å¯¹éåå 容çæ·è´ï¼ä¹å°±æ¯æ·±æ·è´ã
ããä¸é¢æ们就æ¥æ¢è®¨ä¸ä¸ã
ããIosæä¾äºcopyåmutablecopyæ¹æ³ï¼é¡¾åæä¹ï¼copyå°±æ¯å¤å¶äºä¸ä¸ªimutableç对象ï¼èmutablecopyå°±æ¯å¤å¶äºä¸ä¸ªmutableç对象ã以ä¸å°ä¸¾å 个ä¾åæ¥è¯´æã
ãã1. ç³»ç»çé容å¨ç±»å¯¹è±¡
ããè¿éæçæ¯NSString,NSNumberççä¸ç±»ç对象ã
ããNSString *string = @"origion";
ããNSString *stringCopy = [string copy];
ããNSMutableString *stringMCopy = [string mutableCopy];
ãã[stringMCopy appendString:@"!!"];
ããæ¥çå åå¯ä»¥åç°ï¼stringåstringCopyæåçæ¯åä¸åå ååºå(åå«appleå¼±å¼ç¨weak reference)ï¼æ¤æ¶stringCopyçå¼ç¨è®¡æ°åstringçä¸æ ·é½ä¸º2ãèstringMCopyåæ¯æ们æ说ççæ£æä¹ä¸çå¤å¶ï¼ç³»ç»ä¸ºå ¶åé äºæ°å åï¼ä½æéææåçå符串è¿æ¯åstringææçä¸æ ·ã
ããåçä¸é¢çä¾åï¼
ããNSMutableString *string = [NSMutableString stringWithString: @"origion"];
ããNSString *stringCopy = [string copy];
ããNSMutableString *mStringCopy = [string copy];
ããNSMutableString *stringMCopy = [string mutableCopy];
ãã[mStringCopy appendString:@"mm"];//error
ãã[string appendString:@" origion!"];
ãã[stringMCopy appendString:@"!!"];
ãã以ä¸å个NSString对象æåé çå åé½æ¯ä¸ä¸æ ·çãä½æ¯å¯¹äºmStringCopyå ¶å®æ¯ä¸ªimutable对象ï¼æ以ä¸è¿°ä¼æ¥éã
ãã对äºç³»ç»çé容å¨ç±»å¯¹è±¡ï¼æ们å¯ä»¥è®¤ä¸ºï¼å¦æ对ä¸ä¸å¯å对象å¤å¶ï¼copyæ¯æéå¤å¶ï¼æµ æ·è´ï¼åmutableCopyå°±æ¯å¯¹è±¡å¤å¶ï¼æ·±æ·è´ï¼ãå¦ææ¯å¯¹å¯å对象å¤å¶ï¼é½æ¯æ·±æ·è´ï¼ä½æ¯copyè¿åç对象æ¯ä¸å¯åçã
ãã2. ç³»ç»ç容å¨ç±»å¯¹è±¡
ããæNSArrayï¼NSDictionaryçã对äºå®¹å¨ç±»æ¬èº«ï¼ä¸é¢è®¨è®ºçç»è®ºä¹æ¯éç¨çï¼éè¦æ¢è®¨çæ¯å¤å¶å容å¨å 对象çååã
ãã//copyè¿åä¸å¯å对象ï¼mutablecopyè¿åå¯å对象
ããNSArray *array1 = [NSArray arrayWithObjects:@"a",@"b",@"c",nil];
ããNSArray *arrayCopy1 = [array1 copy];
ãã//arrayCopy1æ¯åarrayåä¸ä¸ªNSArray对象ï¼æåç¸åç对象ï¼ï¼å æ¬arrayéé¢çå ç´ ä¹æ¯æåç¸åçæé
ããNSLog(@"array1 retain count: %d",[array1 retainCount]);
ããNSLog(@"array1 retain count: %d",[arrayCopy1 retainCount]);
ããNSMutableArray *mArrayCopy1 = [array1 mutableCopy];
ãã//mArrayCopy1æ¯array1çå¯åå¯æ¬ï¼æåç对象åarray1ä¸åï¼ä½æ¯å ¶ä¸çå ç´ åarray1ä¸çå ç´ æåçæ¯åä¸ä¸ªå¯¹è±¡ãmArrayCopy1è¿å¯ä»¥ä¿®æ¹èªå·±ç对象
ãã[mArrayCopy1 addObject:@"de"];
ãã[mArrayCopy1 removeObjectAtIndex:0];
ããarray1åarrayCopy1æ¯æéå¤å¶ï¼èmArrayCopy1æ¯å¯¹è±¡å¤å¶ï¼mArrayCopy1è¿å¯ä»¥æ¹åæå çå ç´ ï¼å é¤ææ·»å ãä½æ¯æ³¨æçæ¯ï¼å®¹å¨å çå ç´ å 容é½æ¯æéå¤å¶ã
ããä¸é¢ç¨å¦ä¸ä¸ªä¾åæ¥æµè¯ä¸ä¸ã
ããNSArray *mArray1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
ããNSArray *mArrayCopy2 = [mArray1 copy];
ããNSLog(@"mArray1 retain count: %d",[mArray1 retainCount]);
ããNSMutableArray *mArrayMCopy1 = [mArray1 mutableCopy];
ããNSLog(@"mArray1 retain count: %d",[mArray1 retainCount]);
ãã//mArrayCopy2,mArrayMCopy1åmArray1æåçé½æ¯ä¸ä¸æ ·ç对象ï¼ä½æ¯å ¶ä¸çå ç´ é½æ¯ä¸æ ·ç对象ââåä¸ä¸ªæé
ãã//ä¸ä¸åæµè¯
ããNSMutableString *testString = [mArray1 objectAtIndex:0];
ãã//testString = @"1a1";//è¿æ ·ä¼æ¹åtestStringçæéï¼å ¶å®æ¯å°@â1a1â临æ¶å¯¹è±¡èµç»äºtestString
ãã[testString appendString:@" tail"];//è¿æ ·ä»¥ä¸ä¸ä¸ªæ°ç»çé¦å ç´ é½è¢«æ¹åäº
ããç±æ¤å¯è§ï¼å¯¹äºå®¹å¨èè¨ï¼å ¶å ç´ å¯¹è±¡å§ç»æ¯æéå¤å¶ãå¦æéè¦å ç´ å¯¹è±¡ä¹æ¯å¯¹è±¡å¤å¶ï¼å°±éè¦å®ç°æ·±æ·è´ã
ããNSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"first"],[NSStringstringWithString:@"b"],@"c",nil];
ããNSArray *deepCopyArray=[[NSArray alloc] initWithArray: array copyItems: YES];
ããNSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:
ãã[NSKeyedArchiver archivedDataWithRootObject: array]];
ããtrueDeepCopyArrayæ¯å®å ¨æä¹ä¸çæ·±æ·è´ï¼èdeepCopyArrayåä¸æ¯ï¼å¯¹äºdeepCopyArrayå çä¸å¯åå ç´ å ¶è¿æ¯æéå¤å¶ãæè æ们èªå·±å®ç°æ·±æ·è´çæ¹æ³ãå 为å¦æ容å¨çæä¸å ç´ æ¯ä¸å¯åçï¼é£ä½ å¤å¶å®å该对象ä»æ§æ¯ä¸è½æ¹åçï¼å æ¤åªéè¦æéå¤å¶å³å¯ãé¤éä½ å¯¹å®¹å¨å çå ç´ éæ°èµå¼ï¼å¦åæéå¤å¶å³å·²è¶³å¤ã举个ä¾åï¼[[array objectAtIndex:0]appendstring:@âsdâ]åå ¶ä»ç容å¨å 对象并ä¸ä¼åå½±åã[[array objectAtIndex:1]å[[deepCopyArray objectAtIndex:0]尽管æ¯æååä¸åå åï¼ä½æ¯æ们没æåæ³å¯¹å ¶è¿è¡ä¿®æ¹ââå 为å®æ¯ä¸å¯æ¹åçãæ以æéå¤å¶å·²ç»è¶³å¤ãæ以è¿å¹¶ä¸æ¯å®å ¨æä¹ä¸çæ·±æ·è´ï¼ä½æ¯appleçå®æ¹ææ¡£å°å ¶å为deep copyäºï¼å¹¶æ·»å äºcopyåmutablityçå ³ç³»è¯´æï¼æ å¨æ¤åä¸è¯´æ
g