Mantle ทำให้การเขียนเลเยอร์โมเดลอย่างง่ายสำหรับแอปพลิเคชัน Cocoa หรือ Cocoa Touch เป็นเรื่องง่าย
เกิดอะไรขึ้นกับวิธีการเขียนวัตถุโมเดลใน Objective-C
ลองใช้ GitHub API เพื่อการสาธิต โดยทั่วไปแล้วเราจะนำเสนอปัญหา GitHub ใน Objective-C ได้อย่างไร
typedef enum : NSUInteger { GHIssueStateเปิด GHIssueStateปิดแล้ว } GHIssueState;@interface GHIssue : NSObject <NSCoding, NSCopying>@property (ไม่ใช่อะตอมมิก, คัดลอก, อ่านอย่างเดียว) NSURL *URL;@property (ไม่ใช่อะตอมมิก, คัดลอก, อ่านอย่างเดียว) NSURL *HTMLURL;@property (ไม่ใช่อะตอมมิก, คัดลอก, อ่านอย่างเดียว) NSNumber * number;@property (ไม่ใช่อะตอมมิก, มอบหมาย, อ่านอย่างเดียว) GHIssueState state;@property (ไม่ใช่อะตอมมิก, คัดลอก, อ่านอย่างเดียว) NSString *reporterLogin;@property (ไม่ใช่อะตอมมิก, คัดลอก, อ่านอย่างเดียว) NSDate *updatedAt;@property (ไม่ใช่อะตอมมิก, แข็งแกร่ง, อ่านอย่างเดียว) GHUser *มอบหมาย;@property (ไม่ใช่อะตอมมิก, คัดลอก, อ่านอย่างเดียว) NSDate *ดึงข้อมูลAt;@property (ไม่ใช่อะตอมมิก, คัดลอก) NSString *title;@property (ไม่ใช่อะตอมมิก, คัดลอก) NSString *เนื้อหา; - (id)initWithDictionary:(NSDictionary *)dictionary;@end
@ การดำเนินการ GHIssue+ (NSDateFormatter *) dateFormatter {NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.locale = [[NSLocale จัดสรร] initWithLocaleIdentifier:@"en_US_POSIX"]; dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss'Z'";ส่งคืน dateFormatter; - - (id)initWithDictionary:(NSDictionary *)พจนานุกรม { self = [self init]; if (self == nil) ให้คืนค่าศูนย์; _URL = [NSURL URLWithString:พจนานุกรม[@"url"]]; _HTMLURL = [NSURL URLWithString:dictionary[@"html_url"]]; _number = พจนานุกรม[@"number"];if ([พจนานุกรม[@"state"] isEqualToString:@"open"]) { _state = GHIssueStateOpen; } อื่นถ้า ([พจนานุกรม[@"state"] isEqualToString:@"closed"]) { _state = GHIssueStateClosed; - _title = [พจนานุกรม[@"title"] สำเนา]; _ดึงข้อมูลAt = [วันที่ NSDate]; _body = [พจนานุกรม[@"body"] สำเนา]; _reporterLogin = [พจนานุกรม[@"ผู้ใช้"][@"login"] สำเนา]; _assignee = [[GHUser จัดสรร] initWithDictionary:dictionary[@"Assignee"]]; _updatedAt = [self.class.dateFormatter dateFromString:dictionary[@"updated_at"]];ส่งคืนตัวเอง; - - (id)initWithCoder:(NSCoder *)coder { self = [self init]; if (self == nil) ให้คืนค่าศูนย์; _URL = [ตัวเข้ารหัสถอดรหัสObjectForKey:@"URL"]; _HTMLURL = [ตัวเข้ารหัส decodeObjectForKey:@"HTMLURL"]; _number = [ตัวเข้ารหัสถอดรหัสObjectForKey:@"number"]; _state = [ถอดรหัสรหัส UnsignedIntegerForKey:@"state"]; _title = [โค้ดเดอร์ decodeObjectForKey:@"title"]; _ดึงข้อมูลAt = [วันที่ NSDate]; _body = [โค้ดเดอร์ decodeObjectForKey:@"body"]; _reporterLogin = [โค้ดเดอร์ decodeObjectForKey:@"reporterLogin"]; _assignee = [โค้ดเดอร์ decodeObjectForKey:@"ผู้มอบหมาย"]; _updatedAt = [coder decodeObjectForKey:@"updatedAt"];ส่งคืนตัวเอง; - - (เป็นโมฆะ)encodeWithCoder:(NSCoder *)coder {if (self.URL != nil) [coder encodeObject:self.URL forKey:@"URL"];if (self.HTMLURL != nil) [coder encodeObject:self .HTMLURL forKey:@"HTMLURL"];if (self.number != nil) [coder encodeObject:self.number forKey:@"number"];if (self.title != nil) [coder encodeObject:self.title forKey:@"title"];if (self.body != nil) [coder encodeObject:self.body forKey: @"body"];if (self.reporterLogin != ไม่มี) [coder encodeObject:self.reporterLogin forKey:@"reporterLogin"];if (self.assignee != nil) [coder encodeObject:self.assignee forKey:@"assignee"];if (self.updatedAt != nil) [coder encodeObject:self.updatedAt forKey: @"อัพเดตแล้ว"]; [เข้ารหัส encodeUnsignedInteger:self.state forKey:@"state"]; - - (id)copyWithZone:(NSZone *)โซน { GHIssue *issue = [[self.class allocWithZone:zone] init]; ปัญหา -> _URL = self.URL; ปัญหา->_HTMLURL = self.HTMLURL; ปัญหา -> _number = self.number; ปัญหา -> _state = self.state; issue->_reporterLogin = self.reporterLogin; ปัญหา->_มอบหมาย = self.Assignee; ปัญหา -> _updatedAt = self.updatedAt; issue.title = self.title; issue->_retrivedAt = [วันที่ NSDate]; issue.body = self.body;ปัญหาการส่งคืน; - - (NSUInteger) แฮช {return self.number.hash; - - (BOOL)isEqual:(GHIssue *)issue {ถ้า (![issue isKindOfClass:GHIssue.class]) return NO;return [self.number isEqual:issue.number] && [self.title isEqual:issue.title] && [self.body isEqual:issue.body]; }@จบ
โอ้โห นั่นเป็นเรื่องสำเร็จรูปมากมายสำหรับบางสิ่งที่เรียบง่าย! และถึงกระนั้นก็ยังมีปัญหาบางอย่างที่ตัวอย่างนี้ไม่ได้กล่าวถึง:
ไม่มีวิธีอัปเดต GHIssue
ด้วยข้อมูลใหม่จากเซิร์ฟเวอร์
ไม่มีทางที่จะเปลี่ยน GHIssue
กลับ เป็น JSON ได้
GHIssueState
ไม่ควรเข้ารหัสตามที่เป็นอยู่ หากแจงนับเปลี่ยนแปลงในอนาคต ไฟล์เก็บถาวรที่มีอยู่อาจใช้งานไม่ได้
หากอินเทอร์เฟซของ GHIssue
เปลี่ยนไปในอนาคต ไฟล์เก็บถาวรที่มีอยู่อาจเสียหายได้
Core Data แก้ปัญหาบางอย่างได้ดีมาก หากคุณต้องการดำเนินการสืบค้นที่ซับซ้อนกับข้อมูลของคุณ จัดการกราฟวัตถุขนาดใหญ่ที่มีความสัมพันธ์มากมาย หรือรองรับการเลิกทำและทำซ้ำ Core Data เหมาะสมเป็นอย่างยิ่ง
อย่างไรก็ตาม มันมีจุดที่น่าเจ็บปวดอยู่ 2-3 ประการ:
ยังมีแบบสำเร็จรูปอีกมาก ออบเจ็กต์ที่ได้รับการจัดการจะลดขั้นตอนสำเร็จรูปบางส่วนที่เห็นด้านบน แต่ Core Data มีมากมายในตัวมันเอง การตั้งค่าสแต็ก Core Data อย่างถูกต้อง (ด้วยร้านค้าถาวรและผู้ประสานงานร้านค้าถาวร) และการดำเนินการดึงข้อมูลอาจใช้โค้ดหลายบรรทัด
มันยากที่จะทำให้ถูกต้อง แม้แต่นักพัฒนาที่มีประสบการณ์ก็สามารถทำผิดพลาดได้เมื่อใช้ Core Data และเฟรมเวิร์กก็ไม่ยอมให้อภัย
หากคุณเพียงพยายามเข้าถึงออบเจ็กต์ JSON บางอย่าง Core Data อาจทำงานหนักมากโดยได้ประโยชน์เพียงเล็กน้อย
อย่างไรก็ตาม หากคุณใช้หรือต้องการใช้ Core Data ในแอปของคุณอยู่แล้ว Mantle ก็ยังคงเป็นเลเยอร์การแปลที่สะดวกระหว่าง API และออบเจ็กต์โมเดลที่ได้รับการจัดการของคุณ
ป้อน MTLModel นี่คือลักษณะของ GHIssue
ที่สืบทอดมาจาก MTLModel
:
typedef enum : NSUInteger { GHIssueStateเปิด GHIssueStateปิดแล้ว } GHIssueState;@interface GHIssue : MTLModel <MTLJSONSerializing>@property (ไม่ใช่อะตอมมิก, คัดลอก, อ่านอย่างเดียว) NSURL *URL;@property (ไม่ใช่อะตอมมิก, คัดลอก, อ่านอย่างเดียว) NSURL *HTMLURL;@property (ไม่ใช่อะตอมมิก, คัดลอก, อ่านอย่างเดียว) NSNumber *number; @property (ไม่ใช่อะตอมมิก, มอบหมาย, อ่านอย่างเดียว) GHIssueState state;@property (ไม่ใช่อะตอมมิก, คัดลอก, อ่านอย่างเดียว) NSString *reporterLogin;@property (ไม่ใช่อะตอมมิก, แข็งแกร่ง, อ่านอย่างเดียว) GHUser *ผู้มอบหมาย;@property (ไม่ใช่อะตอมมิก, คัดลอก, อ่านอย่างเดียว) NSDate *updatedAt;@property (ไม่ใช่อะตอมมิก, คัดลอก) NSString * title;@property (ไม่ใช่อะตอมมิก, คัดลอก) NSString *body;@property (ไม่ใช่อะตอมมิก, คัดลอก, อ่านอย่างเดียว) NSDate *ดึงข้อมูลเมื่อ;@end
@ การดำเนินการ GHIssue+ (NSDateFormatter *) dateFormatter {NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.locale = [[NSLocale จัดสรร] initWithLocaleIdentifier:@"en_US_POSIX"]; dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss'Z'";ส่งคืน dateFormatter; - + (NSDictionary *)JSONKeyPathsByPropertyKey {return @{@"URL": @"url",@"HTMLURL": @"html_url",@"number": @"number",@"state": @"state", @"reporterLogin": @"user.login",@"มอบหมาย": @"มอบหมาย",@"updatedAt": @"อัพเดต_at"}; - + (NSValueTransformer *)URLJSONTransformer {ส่งคืน [NSValueTransformer valueTransformerForName:MTLURLValueTransformerName]; - + (NSValueTransformer *)HTMLURLJSONTransformer {ส่งคืน [NSValueTransformer valueTransformerForName:MTLURLValueTransformerName]; - + (NSValueTransformer *)stateJSONTransformer {ส่งคืน [NSValueTransformer mtl_valueMappingTransformerWithDictionary:@{@"open": @(GHIssueStateOpen),@"ปิด": @(GHIssueStateClosed) - - + (NSValueTransformer *) มอบหมาย JSONTransformer { ส่งคืน [พจนานุกรม MTLJSONAdapter TransformerWithModelClass: GHUser.class]; - + (NSValueTransformer *)updatedAtJSONTransformer {ส่งคืน [MTLValueTransformer TransformerUsingForwardBlock:^id(NSString *dateString, BOOL *success, NSError *__autoreleasing *error) {return [self.dateFormatter dateFromString:dateString]; } ReverseBlock:^id(NSDate *date, BOOL *success, NSError *__autoreleasing *error) {return [self.dateFormatter stringFromDate:date]; - - - (ประเภทอินสแตนซ์) initWithDictionary: (NSDictionary *) ข้อผิดพลาด dictionaryValue: (NSError **) ข้อผิดพลาด { self = [super initWithDictionary:dictionaryValue error:error];if (self == nil) return nil;// เก็บค่าที่ต้องกำหนดในเครื่องเมื่อเริ่มต้น _retrievedAt = [NSDate date];return self; }@จบ
สิ่งที่ขาดหายไปจากเวอร์ชันนี้คือการใช้งานของ <NSCoding>
, <NSCopying>
, -isEqual:
และ -hash
ด้วยการตรวจสอบการประกาศ @property
ที่คุณมีในคลาสย่อยของคุณ MTLModel
จึงสามารถจัดเตรียมการใช้งานเริ่มต้นสำหรับวิธีการเหล่านี้ทั้งหมดได้
ปัญหาของตัวอย่างดั้งเดิมทั้งหมดได้รับการแก้ไขเช่นกัน:
ไม่มีวิธีอัปเดต
GHIssue
ด้วยข้อมูลใหม่จากเซิร์ฟเวอร์
MTLModel
มีเมธอด -mergeValuesForKeysFromModel:
ที่ขยายได้ ซึ่งช่วยให้ระบุได้ง่ายว่าควรรวมข้อมูลโมเดลใหม่อย่างไร
ไม่มีทางที่จะเปลี่ยน
GHIssue
กลับ เป็น JSON ได้
นี่คือจุดที่หม้อแปลงแบบพลิกกลับมีประโยชน์จริงๆ +[MTLJSONAdapter JSONDictionaryFromModel:error:]
สามารถเปลี่ยนอ็อบเจ็กต์โมเดลใดๆ ที่สอดคล้องกับ <MTLJSONSerializing>
กลับเป็นพจนานุกรม JSON +[MTLJSONAdapter JSONArrayFromModels:error:]
เหมือนกัน แต่เปลี่ยนอาร์เรย์ของอ็อบเจ็กต์โมเดลให้เป็นอาร์เรย์ JSON ของพจนานุกรม
หากอินเทอร์เฟซของ
GHIssue
เปลี่ยนไปในอนาคต ไฟล์เก็บถาวรที่มีอยู่อาจเสียหายได้
MTLModel
จะบันทึกเวอร์ชันของวัตถุโมเดลที่ใช้สำหรับการเก็บถาวรโดยอัตโนมัติ เมื่อยกเลิกการเก็บถาวร -decodeValueForKey:withCoder:modelVersion:
จะถูกเรียกใช้หากถูกแทนที่ ทำให้คุณสะดวกในการอัปเกรดข้อมูลเก่า
ในการซีเรียลไลซ์ออบเจ็กต์โมเดลของคุณจากหรือลงใน JSON คุณต้องใช้งาน <MTLJSONSerializing>
ในคลาสย่อย MTLModel
ของคุณ สิ่งนี้ช่วยให้คุณใช้ MTLJSONAdapter
เพื่อแปลงออบเจ็กต์โมเดลของคุณจาก JSON และด้านหลัง:
NSError *ข้อผิดพลาด = ไม่มี; XYUser *user = [MTLJSONAdapter modelOfClass:XYUser.class fromJSONDictionary:JSONDictionary ข้อผิดพลาด:&ข้อผิดพลาด];
NSError *error = nil;NSDictionary *JSONDictionary = [MTLJSONAdapter JSONDictionaryFromModel:ข้อผิดพลาดของผู้ใช้:&ข้อผิดพลาด];
+JSONKeyPathsByPropertyKey
พจนานุกรมที่ส่งคืนโดยเมธอดนี้ระบุว่าคุณสมบัติของออบเจ็กต์โมเดลของคุณแมปกับคีย์ในการแสดง JSON อย่างไร ตัวอย่างเช่น:
@interface XYUser : MTLModel@property (อ่านอย่างเดียว, ไม่ใช่อะตอมมิก, คัดลอก) NSString *name;@property (อ่านอย่างเดียว, ไม่ใช่อะตอมมิก, แข็งแกร่ง) NSDate *createdAt;@property (อ่านอย่างเดียว, ไม่ใช่อะตอมมิก, มอบหมาย, getter = isMeUser) BOOL meUser;@property ( อ่านอย่างเดียว ไม่ใช่อะตอมมิก แข็งแกร่ง) XYHelper *helper;@end@implementation XYUser+ (NSDictionary *)JSONKeyPathsByPropertyKey {return @{@"name": @"name",@"createdAt": @"created_at"}; - - (ประเภทอินสแตนซ์) initWithDictionary: (NSDictionary *) ข้อผิดพลาด dictionaryValue: (NSError **) ข้อผิดพลาด { self = [super initWithDictionary:dictionaryValue error:error];if (self == nil) ส่งคืนศูนย์; _helper = [XYHelper helperWithName:self.name createAt:self.createdAt];คืนตัวเอง; }@จบ
ในตัวอย่างนี้ คลาส XYUser
ประกาศคุณสมบัติสี่ประการที่ Mantle จัดการด้วยวิธีที่แตกต่างกัน:
name
ถูกแมปกับคีย์ที่มีชื่อเดียวกันในการเป็นตัวแทน JSON
createdAt
จะถูกแปลงเป็นกรณีงูที่เทียบเท่า
meUser
ไม่ได้รับการซีเรียลไลซ์เป็น JSON
helper
จะถูกเตรียมใช้งานทันทีหลังจากการดีซีเรียลไลซ์ JSON
ใช้ -[NSDictionary mtl_dictionaryByAddingEntriesFromDictionary:]
หากซูเปอร์คลาสของโมเดลของคุณยังใช้ MTLJSONSerializing
เพื่อรวมการแมปเข้าด้วยกัน
หากคุณต้องการแมปคุณสมบัติทั้งหมดของคลาส Model กับตัวเอง คุณสามารถใช้เมธอดตัวช่วย +[NSDictionary mtl_identityPropertyMapWithModel:]
ได้
เมื่อทำการดีซีเรียลไลซ์ JSON โดยใช้ +[MTLJSONAdapter modelOfClass:fromJSONDictionary:error:]
คีย์ JSON ที่ไม่สอดคล้องกับชื่อคุณสมบัติหรือมีการแมปที่ชัดเจนจะถูกละเว้น:
NSDictionary *JSONDictionary = @{@"name": @"john",@"created_at": @"2013/07/02 16:40:00 +0000",@"plan": @"lite"}; XYUser *user = [MTLJSONAdapter modelOfClass:XYUser.class fromJSONDictionary:JSONDictionary ข้อผิดพลาด:&ข้อผิดพลาด];
ในที่นี้ plan
จะถูกละเว้นเนื่องจากไม่ตรงกับชื่อคุณสมบัติของ XYUser
และไม่ได้แมปใน +JSONKeyPathsByPropertyKey
+JSONTransformerForKey:
ใช้วิธีที่เป็นทางเลือกนี้เพื่อแปลงคุณสมบัติจากประเภทอื่นเมื่อทำการดีซีเรียลไลซ์จาก JSON
+ (NSValueTransformer *)JSONTransformerForKey:(NSString *)key { if ([key isEqualToString:@"createdAt"]) { return [NSValueTransformer valueTransformerForName:XYDateValueTransformerName]; } return nil; }
key
คือคีย์ที่ใช้กับวัตถุโมเดลของคุณ ไม่ใช่คีย์ JSON ดั้งเดิม โปรดทราบว่าหากคุณเปลี่ยนชื่อคีย์โดยใช้ +JSONKeyPathsByPropertyKey
เพื่อความสะดวกเพิ่มเติม หากคุณใช้ +<key>JSONTransformer
MTLJSONAdapter
จะใช้ผลลัพธ์ของเมธอดนั้นแทน ตัวอย่างเช่น วันที่ที่แสดงโดยทั่วไปเป็นสตริงใน JSON สามารถแปลงเป็น NSDate
ได้ดังนี้:
return [MTLValueTransformer TransformerUsingForwardBlock:^id(NSString *dateString, BOOL *success, NSError *__autoreleasing *error) {return [self.dateFormatter dateFromString:dateString]; } ReverseBlock:^id(NSDate *date, BOOL *success, NSError *__autoreleasing *error) {return [self.dateFormatter stringFromDate:date]; - -
หากหม้อแปลงสามารถพลิกกลับได้ หม้อแปลงจะถูกใช้เมื่อซีเรียลไลซ์อ็อบเจ็กต์ลงใน JSON ด้วย
+classForParsingJSONDictionary:
หากคุณกำลังใช้คลัสเตอร์คลาส ให้ใช้เมธอดทางเลือกนี้เพื่อกำหนดคลาสย่อยของคลาสฐานของคุณที่ควรใช้เมื่อทำการดีซีเรียลไลซ์อ็อบเจ็กต์จาก JSON
@interface XYMessage : MTLModel@end@interface XYTextMessage: XYMessage@property (อ่านอย่างเดียว ไม่ใช่อะตอมมิก คัดลอก) NSString *body;@end@interface XYPictureMessage : XYMessage@property (อ่านอย่างเดียว ไม่ใช่อะตอมมิก แข็งแกร่ง) NSURL *imageURL;@end@implementation XYMessage+ (Class)classForParsingJSONDictionary:(NSDictionary *)JSONDictionary {ถ้า (JSONDictionary[@"image_url"] != ไม่มี) {return XYPictureMessage.class; }ถ้า (JSONDictionary[@"body"] != ไม่มี) {return XYTextMessage.class; }NSAssert(NO, @"ไม่มีคลาสที่ตรงกันสำหรับพจนานุกรม JSON '%@'.", JSONDictionary);ส่งคืนตัวเอง; }@จบ
MTLJSONAdapter
จะเลือกคลาสตามพจนานุกรม JSON ที่คุณส่ง:
NSDictionary *textMessage = @{@"id": @1,@"body": @"Hello World!"};NSDictionary *pictureMessage = @{@"id": @2,@"image_url": @"http: //example.com/lolcat.gif"}; XYTextMessage *messageA = [MTLJSONAdapter modelOfClass:XYMessage.class fromJSONDictionary:textMessage ข้อผิดพลาด:NULL]; XYPictureMessage *messageB = [MTLJSONAdapter modelOfClass:XYMessage.class fromJSONDictionary:pictureMessage ข้อผิดพลาด:NULL];
แมนเทิลจะไม่คงวัตถุของคุณไว้ให้คุณโดยอัตโนมัติ อย่างไรก็ตาม MTLModel
ไม่สอดคล้องกับ <NSCoding>
ดังนั้นวัตถุโมเดลจึงสามารถเก็บถาวรลงดิสก์ได้โดยใช้ NSKeyedArchiver
หากคุณต้องการบางสิ่งที่ทรงพลังกว่านี้ หรือต้องการหลีกเลี่ยงการเก็บโมเดลทั้งหมดไว้ในหน่วยความจำในคราวเดียว Core Data อาจเป็นตัวเลือกที่ดีกว่า
Mantle รองรับเป้าหมายการปรับใช้แพลตฟอร์มต่อไปนี้:
macOS 10.10+
ไอโอเอส 9.0+
ทีวี OS 9.0+
วอทช์ OS 2.0+
วิธีเพิ่ม Mantle ให้กับแอปพลิเคชันของคุณ:
เพิ่มพื้นที่เก็บข้อมูล Mantle เป็นโมดูลย่อยของพื้นที่เก็บข้อมูลแอปพลิเคชันของคุณ
เรียกใช้ git submodule update --init --recursive
จากภายในโฟลเดอร์ Mantle
ลากและวาง Mantle.xcodeproj
ลงในโปรเจ็กต์ Xcode ของแอปพลิเคชันของคุณ
บนแท็บ "ทั่วไป" ของเป้าหมายแอปพลิเคชันของคุณ ให้เพิ่ม Mantle.framework
ลงใน "Embedded Binaries"
หากคุณจะพัฒนา Mantle ด้วยตัวเองแทน ให้ใช้ไฟล์ Mantle.xcworkspace
เพียงเพิ่ม Mantle ลงใน Cartfile
ของคุณ :
github "Mantle/Mantle"
เพิ่ม Mantle ให้กับ Podfile
ของคุณภายใต้เป้าหมายการสร้างที่ต้องการใช้ใน:
target 'MyAppOrFramework' do pod 'Mantle' end
จากนั้นเรียกใช้ pod install
ภายใน Terminal หรือแอพ CocoaPods
หากคุณกำลังเขียนแอปพลิเคชัน ให้เพิ่ม Mantle ลงในการขึ้นต่อกันของโปรเจ็กต์ของคุณโดยตรงภายใน Xcode
หากคุณกำลังเขียนแพ็คเกจที่ต้องใช้ Mantle เป็นการพึ่งพา ให้เพิ่มมันเข้าไปในรายการ dependencies
ในรายการ Package.swift
ตัวอย่างเช่น:
dependencies: [ .package(url: "https://github.com/Mantle/Mantle.git", .upToNextMajor(from: "2.0.0")) ]
Mantle เปิดตัวภายใต้ใบอนุญาต MIT ดูใบอนุญาต.md
มีคำถาม? กรุณาเปิดประเด็น!