2011-09-09 29 views
9

Trong một số bảo trì của một số multitouch "vẽ trên màn hình" mã, tôi đã gặp một lỗi liên quan đến cách tham chiếu đến trường hợp chạm nên được thiết lập giữa touchesBegan: withEvent :, touchesMoved: withEvent: và touchesEnded: withEvent :.Cách theo dõi các điểm chạm theo cách nhất quán giữa các lần chạmBắt đầu: và chạm vàoĐược cấp :?

Mã này sử dụng một trường hợp NSDictionary để lưu trữ tài liệu tham khảo của chạm trong touchesBegan: withEvent :, như sau:

for (UITouch *touch in touches]) { 
    NSValue *touchValue = [NSValue valueWithPointer:touch]; 
    NSString *key = [NSString stringWithFormat:@"%@", touchValue]; 
    [myTouches setValue:squiggle forKey:key]; 
} 

Và lấy chúng trong touchesEnded: withEvent: theo cách này:

for (UITouch *touch in touches) { 
    NSValue *touchValue = [NSValue valueWithPointer:touch]; 
    NSString *key = [NSString stringWithFormat:@"%@", touchValue]; 
    NSObject *valueFromDictionary = [myTouches valueForKey:key]; 
    [myTouches removeObjectForKey:key]; 
} 

Trong bit cuối cùng của mã này, valueFromDictionary xảy ra thỉnh thoảng là nil, vì khoá không được từ điển biết đến. Thỉnh thoảng, tôi có nghĩa là khoảng 1% thời gian.

Bây giờ bối cảnh được thiết lập, câu hỏi của tôi là:

  1. Bất cứ ý tưởng tại sao mã này là lỗi? Tôi không chắc chắn lý do tại sao nó không hoạt động, đặc biệt là do tần số rất thấp của lỗi

  2. Some doc from Apple khẳng định sử dụng địa chỉ của đối tượng UITouch là các phím : nhưng nó có nghĩa là sử dụng đối tượng NSValue * thay vì các đối tượng NSString * ( và do đó sử dụng CFDictionaryRef thay vì NSDictionary vì thực tế UITouch không triển khai giao thức sao chép). Làm thế nào để lưu trữ một đại diện NSString của địa chỉ thay vì bản thân NSValue không thể là một giải pháp dễ dàng để có thể sử dụng NSDictionary? Cập nhật: Apple đã cập nhật trang và xóa ví dụ về lưu trữ UITouch qua NSString và chỉ đề cập đến giải pháp CFDictionaryRef không phải đối tượng.

Tôi e là tôi xa C và các công cụ con trỏ và cần trợ giúp để hiểu lý do có lỗi trong mã này.

Trả lời

4

Khi bạn sử dụng stringWithFormat để chuyển đổi thể hiện NSValue thành chuỗi, tôi tin rằng bạn chủ yếu gọi [touchValue description], mà tôi không chắc chắn đảm bảo kết quả nhất quán. Ví dụ, nếu mô tả bao gồm một con trỏ đến bản thân NSValue, như nhiều đối tượng làm gì? Trong trường hợp đó, hai trường hợp NSValue khác nhau lưu trữ cùng một con trỏ chính xác sẽ tạo ra các khóa chuỗi khác nhau.

Tôi muốn được quan tâm trong nhìn thấy những gì xảy ra khi bạn chạy các đoạn mã sau:

for (UITouch *touch in touches) { 
    NSValue *touchValue = [NSValue valueWithPointer:touch]; 
    NSString *key = [NSString stringWithFormat:@"%@", touchValue]; 
    NSObject *valueFromDictionary = [myTouches valueForKey:key]; 

    if (valueFromDictionary == nil) { 
    NSLog(@"%@", [myTouches allKeys]); 
    NSLog(@"%@", key); 
    } 

    [myTouches removeObjectForKey:key]; 
} 

Điều này sẽ cho chúng ta biết chính xác những gì đang thay đổi về phím. Nhưng nếu bạn chỉ muốn sửa chữa vấn đề bạn đang gặp phải, tôi đặt cược nó sẽ làm việc nếu bạn sử dụng đối tượng NSValue như một khóa trực tiếp, vì nó phù hợp với giao thức NSCopying. Về cơ bản, con trỏ (UITouch *) chỉ là một số xác định duy nhất nơi mà cá thể UITouch được lưu trong bộ nhớ. NSValue gói gọn số này giống như cách NSNumber, vì vậy bạn có thể nghĩ nó giống như một khóa số trong mảng.Chừng nào các liên lạc tiếp tục chiếm cùng một vị trí trong bộ nhớ (như Apple cho thấy nó sẽ), cần làm việc một cách hoàn hảo như một chìa khóa, và mã của bạn sẽ đơn giản hơn:

(touchesBegan: withEvent :)

for (UITouch *touch in touches]) { 
    NSValue *key = [NSValue valueWithPointer:touch]; 
    [myTouches setValue:squiggle forKey:key]; 
} 

(touchesEnded: withEvent :)

for (UITouch *touch in touches) { 
    NSValue *key = [NSValue valueWithPointer:touch]; 
    NSObject *valueFromDictionary = [myTouches valueForKey:key]; 
    [myTouches removeObjectForKey:key]; 
} 

có thực sự không có lý do gì để nhốt mình vào phím chuỗi, trừ khi bạn cần phải sử dụng giá trị khóa mã hóa hoặc serialize điển vào một danh sách bất động sản.

+0

Tôi đã thử giải pháp NSValue nhưng có cùng kết quả so với NSString: hoạt động độc đáo 99% thời gian nhưng vẫn còn 1% lỗi này. Bây giờ tôi cho rằng đó là lỗi của Apple (thực tế là trang tôi đã đề cập trong câu hỏi của tôi vừa được cập nhật cách đây vài ngày là một đầu mối thậm chí nhân viên Apple không chắc chắn về vấn đề này) HOẶC một vấn đề đồng thời giữa thời điểm Tôi đặt dữ liệu vào và lấy dữ liệu ra. –

-1

Không sử dụng

NSString *key = [NSString stringWithFormat:@"%@", touchValue]; 

cho khóa. Cách tốt nhất là nên đặt giá trị con trỏ cảm ứng như một chìa khóa

id key = touch; 

hoặc nếu bạn thích chuỗi, sử dụng trường hợp này:

NSString *key = [NSString stringWithFormat:@"%x", touch]; // %x prints hex value of touch 
+0

Giải pháp% x không thể hoạt động: bạn đang lưu trữ giá trị của con trỏ thay vì địa chỉ bạn trỏ đến (tôi thực sự nhận ra điều này sau khi đã thử nghiệm: lỗi xuất hiện 100% thời gian thay vì 1%) –

+0

Có vẻ lạ. Bạn có thể thiết lập các điểm ngắt trong phương thức 'touchesBegan' và 'touchesEnded' và so sánh các địa chỉ của 'UITouch * touch' (và cũng so sánh nó với giá trị được lưu vào khóa qua @ "x")? Như tôi biết tất cả các giá trị này phải bằng nhau. Tôi sử dụng cùng một phương pháp trong ứng dụng của tôi và nó hoạt động. Vui lòng kiểm tra xem bạn có vượt qua 'chạm' nhưng không phải là 'touchValue' đến @ "x" hay không. – brigadir

4

Bạn có thể sử dụng hash của UITouch tài sản cho cả ObjC và Swift. Nó tương tự cho cùng một liên lạc trên nhiều sự kiện (Lên, Xuống, Di chuyển, v.v.). Đây là một số Int nhưng bạn có thể chuyển đổi nó thành String

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