5

Trong nhiệm vụ cập nhật mô hình Dữ liệu cốt lõi trong dự án iOS của tôi, tôi đang truy vấn máy chủ cho các đối tượng JSON tương ứng - ở một mức độ nào đó - với các thực thể được quản lý của mô hình của tôi. Kết quả cuối cùng mà tôi đang phấn đấu là một giải pháp cập nhật đáng tin cậy từ đầu ra JSON.Làm cách nào để kiểm tra sự tồn tại và loại thuộc tính dựa trên khóa nhập NSString?

Đối với các ví dụ trong câu hỏi này, tôi sẽ đặt tên cho đối tượng được quản lý dữ liệu lõi existingObj và từ điển JSON deserialized đến updateDict. Phần khó khăn là đối phó với những sự kiện này:

  1. Không phải tất cả các thuộc tính của existingObj có mặt trong updateDict
  2. Không phải tất cả các thuộc tính của updateDict có sẵn trong extistingObj.
  3. Không phải tất cả các loại thuộc tính của existingObj đều khớp với thuộc tính được deserialized JSON. (một số chuỗi có thể cần một wrapper Objective-C tùy chỉnh).
  4. updateDict có thể chứa các giá trị cho các khóa chưa được khởi tạo (nil) trong existingObj.

Điều này có nghĩa là trong khi lặp qua các từ điển được cập nhật, phải có một số kiểm tra thuộc tính qua lại. Trước tiên tôi phải kiểm tra xem các thuộc tính của updateDict tồn tại trong existingObj, sau đó tôi thiết lập giá trị sử dụng KVC, như vậy:

// key is an NSString, e.g. @"displayName" 
if ([existingObj respondsToSelector:NSSelectorFromString(key)) { 
    [existingObj setValue:[updateDict objectForKey:key] forKey:key]; 
} 

Mặc dù phần này tác phẩm, tôi không thích thực tế rằng tôi thực sự thử nghiệm cho displayName như là một getter, trong khi tôi về để gọi setDisplayName: setter (gián tiếp thông qua KVC). Những gì tôi muốn là một cái gì đó như [currentObj hasWritablePropertyWithName : key], nhưng một cái gì đó mà tôi không thể tìm thấy.

Điều này làm cho truy vấn con A: Làm thế nào để kiểm tra cho trình thiết lập thuộc tính, nếu bạn chỉ có tên của thuộc tính?

Phần tiếp theo là nơi tôi muốn tự động nhận dạng thuộc tính dựa trên loại của chúng. Nếu cả hai số updateDictexistingObj đều có NSString cho khóa @ "displayName", việc đặt giá trị mới rất dễ dàng. Tuy nhiên, nếu updateDict chứa một NSString cho khóa @ "color" đó là @ "niceShadeOfGreen", tôi muốn biến điều này thành phiên bản UIColor phù hợp. Nhưng làm cách nào để kiểm tra loại thuộc tính nhận trong số existingObj để tôi biết khi nào nên chuyển đổi giá trị và thời điểm chỉ định đơn giản? Tôi đã hy vọng cho một cái gì đó dọc theo dòng của typeOfSelector:

if ([existingObj typeOfSelector:sel] == [[updateDict objectForKey:key] class]) { 
    // regular assignment 
} else { 
    // perform custom assignment 
} 

Tất nhiên đây là boguscode. Tôi không thể dựa vào thử nghiệm loại giá trị của existingObj -property, vì nó có thể được đơn lẻ hóa hoặc nil.

Câu hỏi con B: Làm cách nào để kiểm tra loại thuộc tính, nếu bạn chỉ có tên của thuộc tính?

Tôi đoán là vậy. Tôi nhận ra đây phải là một sự lừa đảo của thứ gì đó đã có ở đây, nhưng tôi không thể tìm thấy nó. Có lẽ các bạn có thể?
Chúc mừng, EP.

P.S. Nếu bạn có một cách tốt hơn để đồng bộ hóa các đối tượng Objective-C tùy chỉnh với các đối tượng JSON được deserialized, hãy chia sẻ! Cuối cùng, kết quả là những gì đếm.

+0

Tôi đề nghị bạn chỉ cần truy vấn 'updateDict' cho các phím * bạn biết * và bỏ qua tất cả phần còn lại. – Costique

+0

Từ ví dụ trên, đó thực sự là một lựa chọn khả thi. Tuy nhiên trong kịch bản thế giới thực, điều này sẽ làm thay đổi đối tượng được quản lý và cập nhật rất phức tạp. Các đối tượng bao gồm hơn 30 khóa/thuộc tính, hầu hết trong số đó là NSString hoặc NSNumber. Nếu có một giải pháp cho câu hỏi trên, việc đồng bộ sẽ không cần sửa đổi khi các kiểu nguyên thủy được thêm vào hoặc sửa đổi ở cả hai bên. – epologee

Trả lời

27

Nếu bạn muốn truy vấn xem một đối tượng có một setter cho một chìa khóa KVC cho gọi key tương ứng với một tài sản kê khai, bạn cần phải kiểm tra xem nó phản ứng với một phương pháp selector gọi setKey: (bắt đầu với set, hoa đầu tiên ký tự trong key, thêm dấu hai chấm). Ví dụ,

NSString *key = @"displayName"; 
NSString *setterStr = [NSString stringWithFormat:@"set%@%@:", 
         [[key substringToIndex:1] capitalizedString], 
         [key substringFromIndex:1]]; 

if ([obj respondsToSelector:NSSelectorFromString(setterStr)]) { 
    NSLog(@"found the setter!"); 
    [obj setValue:someValue forKey:key]; 
} 

Hai nhận xét:

  • Mặc dù thuộc tính có thể có setters với những cái tên mà không làm theo các mô hình mô tả ở trên, họ sẽ không KVC phù hợp, vì vậy nó là an toàn để kiểm tra set<Key>: vì bạn đang sử dụng KVC để đặt giá trị tương ứng.

  • KVC không chỉ sử dụng phương thức setter. Nếu không tìm thấy phương thức setter, nó sẽ kiểm tra xem lớp đó có cho phép truy cập trực tiếp vào các biến mẫu không và nếu có, hãy sử dụng biến cá thể để đặt giá trị. Ngoài ra, nếu không có phương thức setter hoặc biến mẫu được tìm thấy, nó sẽ gửi -setValue:forUndefinedKey: đến người nhận, có lớp có thể đã ghi đè việc triển khai tiêu chuẩn mà ném một ngoại lệ. Điều này được mô tả trong số Key-Value Coding Programming Guide. Điều đó nói rằng, nếu bạn luôn sử dụng các thuộc tính, việc kiểm tra phương thức setter phải an toàn.

Đối với câu hỏi thứ hai, không thể truy vấn thời gian chạy để biết lớp Objective-C thực tế của thuộc tính. Từ phối cảnh thời gian chạy, có một loại mã hóa loại triển khai cụ thể cho propertiesgeneral types (chẳng hạn như thông số phương pháp/kiểu trả về). Loại mã hóa này sử dụng một mã hóa đơn (cụ thể là @) cho bất kỳ đối tượng Mục tiêu-C nào, vì vậy kiểu mã hóa của thuộc tính NSString giống với kiểu mã hóa thuộc tính UIColor vì chúng là cả hai lớp Objective-C.

Nếu bạn cần chức năng này, một cách khác là xử lý các lớp của bạn và thêm phương thức lớp trả về từ điển có khóa và loại tương ứng cho mọi thuộc tính (hoặc những thứ bạn quan tâm) được khai báo trong lớp đó và siêu lớp, hoặc có thể một số loại ngôn ngữ mô tả. Bạn phải tự làm điều này và dựa vào thông tin không có sẵn trong thời gian chạy.

+0

Đầu vào rất có giá trị @Bavarious. Tôi không nghĩ về từ điển với các loại tương ứng, đó là giải pháp thanh lịch nhất sofar! Đây có phải là vấn đề thường gặp khi cập nhật mô hình cục bộ từ phản hồi của máy chủ trong JSON không? Có giải pháp tốt hơn để đồng bộ hóa như vậy không? Chúc mừng, EP. – epologee

+0

Điều đó thực sự sẽ là một chủ đề cho một câu hỏi tiếp theo, tôi sẽ đóng câu hỏi này ngay bây giờ. Cảm ơn! – epologee

+0

Điều này là tuyệt vời Bavarious, cảm ơn bạn – shabbirv

Các vấn đề liên quan