Nguy hiểm của phương pháp Lướt trong Objective-C là gì?


235

Tôi đã nghe mọi người nói rằng phương pháp swizzling là một thực hành nguy hiểm. Ngay cả cái tên xôn xao cũng cho thấy đó là một chút gian lận.

Phương thức Swizzling đang sửa đổi ánh xạ để gọi bộ chọn A thực sự sẽ gọi thực hiện B. Một cách sử dụng này là để mở rộng hành vi của các lớp nguồn đóng.

Chúng ta có thể chính thức hóa các rủi ro để bất kỳ ai quyết định có nên sử dụng phương pháp đánh bóng hay không có thể đưa ra quyết định sáng suốt cho dù nó có xứng đáng với những gì họ đang cố gắng làm hay không.

Ví dụ

  • Đặt tên va chạm : Nếu sau này lớp mở rộng chức năng của nó để bao gồm tên phương thức mà bạn đã thêm, nó sẽ gây ra một vấn đề rất lớn. Giảm rủi ro bằng cách đặt tên hợp lý các phương pháp swizzled.

Thật không tốt để có được thứ gì đó mà bạn mong đợi từ mã bạn đã đọc
Martin Babacaev 17/03/2016

điều này nghe có vẻ như là một cách ô uế để làm những gì mà những người trang trí trăn làm rất sạch sẽ
Claudiu

Câu trả lời:


439

Tôi nghĩ rằng đây là một câu hỏi thực sự tuyệt vời, và thật xấu hổ thay vì giải quyết câu hỏi thực sự, hầu hết các câu trả lời đã bỏ qua vấn đề và nói đơn giản là không sử dụng phương pháp đánh bóng.

Sử dụng phương pháp xông khói cũng giống như dùng dao nhọn trong bếp. Một số người sợ dao sắc vì họ nghĩ rằng họ sẽ tự cắt mình rất tệ, nhưng sự thật là dao sắc sẽ an toàn hơn .

Phương pháp swizzling có thể được sử dụng để viết mã tốt hơn, hiệu quả hơn, dễ bảo trì hơn. Nó cũng có thể bị lạm dụng và dẫn đến những con bọ khủng khiếp.

Lý lịch

Như với tất cả các mẫu thiết kế, nếu chúng tôi nhận thức đầy đủ về hậu quả của mẫu, chúng tôi có thể đưa ra quyết định sáng suốt hơn về việc có nên sử dụng nó hay không. Singletons là một ví dụ điển hình cho điều gì đó gây tranh cãi và vì lý do chính đáng - chúng thực sự khó thực hiện đúng. Nhiều người vẫn chọn sử dụng singletons. Điều tương tự có thể được nói về swizzling. Bạn nên hình thành ý kiến ​​của riêng mình một khi bạn hoàn toàn hiểu cả mặt tốt và mặt xấu.

Thảo luận

Dưới đây là một số cạm bẫy của phương pháp swizzling:

  • Phương pháp swizzling không phải là nguyên tử
  • Thay đổi hành vi của mã không sở hữu
  • Xung đột đặt tên có thể
  • Lướt thay đổi đối số của phương thức
  • Thứ tự của các vấn đề
  • Khó hiểu (có vẻ đệ quy)
  • Khó gỡ lỗi

Những điểm này đều hợp lệ và khi giải quyết chúng, chúng ta có thể cải thiện cả sự hiểu biết của chúng ta về phương pháp thay đổi phương pháp cũng như phương pháp được sử dụng để đạt được kết quả. Tôi sẽ đưa từng người một.

Phương pháp swizzling không phải là nguyên tử

Tôi vẫn chưa thấy việc thực hiện phương pháp swizzling an toàn để sử dụng đồng thời 1 . Đây thực sự không phải là vấn đề trong 95% trường hợp bạn muốn sử dụng phương pháp swizzling. Thông thường, bạn chỉ muốn thay thế việc thực hiện một phương thức và bạn muốn việc triển khai đó được sử dụng trong toàn bộ thời gian của chương trình. Điều này có nghĩa là bạn nên thực hiện phương pháp của bạn +(void)load. Các loadphương pháp lớp học được thực hiện nối tiếp vào lúc bắt đầu của ứng dụng. Bạn sẽ không có bất kỳ vấn đề nào với sự tương tranh nếu bạn thực hiện thao tác lộn xộn ở đây. +(void)initializeTuy nhiên, nếu bạn bị cuốn vào , bạn có thể gặp phải tình trạng chạy đua trong quá trình thực hiện chóng mặt và thời gian chạy có thể rơi vào trạng thái kỳ lạ.

Thay đổi hành vi của mã không sở hữu

Đây là một vấn đề với swizzling, nhưng nó là loại toàn bộ vấn đề. Mục tiêu là có thể thay đổi mã đó. Lý do mà mọi người chỉ ra đây là một vấn đề lớn là vì bạn không chỉ thay đổi mọi thứ cho một trường hợp NSButtonmà bạn muốn thay đổi mọi thứ mà thay vào đó là tất cả các NSButtontrường hợp trong ứng dụng của bạn. Vì lý do này, bạn nên thận trọng khi bạn thay đổi, nhưng bạn không cần phải tránh nó hoàn toàn.

Hãy nghĩ về nó theo cách này ... nếu bạn ghi đè một phương thức trong một lớp và bạn không gọi phương thức siêu hạng đó, bạn có thể gây ra vấn đề phát sinh. Trong hầu hết các trường hợp, siêu lớp đang mong đợi phương thức đó được gọi (trừ khi có tài liệu khác). Nếu bạn áp dụng cùng suy nghĩ này cho việc thay đổi, bạn đã giải quyết được hầu hết các vấn đề. Luôn luôn gọi thực hiện ban đầu. Nếu bạn không, có lẽ bạn đang thay đổi quá nhiều để an toàn.

Xung đột đặt tên có thể

Đặt tên xung đột là một vấn đề trong suốt ca cao. Chúng tôi thường xuyên tiền tố tên lớp và tên phương thức trong các thể loại. Thật không may, xung đột đặt tên là một bệnh dịch trong ngôn ngữ của chúng tôi. Tuy nhiên, trong trường hợp bị sưng, họ không cần phải như vậy. Chúng ta chỉ cần thay đổi cách chúng ta nghĩ về phương pháp phồng nhẹ. Hầu hết các vụ nổ được thực hiện như thế này:

@interface NSView : NSObject
- (void)setFrame:(NSRect)frame;
@end

@implementation NSView (MyViewAdditions)

- (void)my_setFrame:(NSRect)frame {
    // do custom work
    [self my_setFrame:frame];
}

+ (void)load {
    [self swizzle:@selector(setFrame:) with:@selector(my_setFrame:)];
}

@end

Điều này chỉ hoạt động tốt, nhưng điều gì sẽ xảy ra nếu my_setFrame:được xác định ở một nơi khác? Vấn đề này không phải là duy nhất để gây xáo trộn, nhưng dù sao chúng ta cũng có thể giải quyết nó. Cách giải quyết có thêm một lợi ích của việc giải quyết các cạm bẫy khác. Đây là những gì chúng tôi làm thay thế:

@implementation NSView (MyViewAdditions)

static void MySetFrame(id self, SEL _cmd, NSRect frame);
static void (*SetFrameIMP)(id self, SEL _cmd, NSRect frame);

static void MySetFrame(id self, SEL _cmd, NSRect frame) {
    // do custom work
    SetFrameIMP(self, _cmd, frame);
}

+ (void)load {
    [self swizzle:@selector(setFrame:) with:(IMP)MySetFrame store:(IMP *)&SetFrameIMP];
}

@end

Mặc dù cái này trông hơi giống Objective-C (vì nó sử dụng các con trỏ hàm), nhưng nó tránh mọi xung đột đặt tên. Về nguyên tắc, nó hoạt động chính xác giống như độ xoáy tiêu chuẩn. Đây có thể là một chút thay đổi đối với những người đã sử dụng swizzling vì nó đã được xác định trong một thời gian, nhưng cuối cùng, tôi nghĩ rằng nó tốt hơn. Phương pháp swizzling được định nghĩa như vậy:

typedef IMP *IMPPointer;

BOOL class_swizzleMethodAndStore(Class class, SEL original, IMP replacement, IMPPointer store) {
    IMP imp = NULL;
    Method method = class_getInstanceMethod(class, original);
    if (method) {
        const char *type = method_getTypeEncoding(method);
        imp = class_replaceMethod(class, original, replacement, type);
        if (!imp) {
            imp = method_getImplementation(method);
        }
    }
    if (imp && store) { *store = imp; }
    return (imp != NULL);
}

@implementation NSObject (FRRuntimeAdditions)
+ (BOOL)swizzle:(SEL)original with:(IMP)replacement store:(IMPPointer)store {
    return class_swizzleMethodAndStore(self, original, replacement, store);
}
@end

Lướt qua bằng cách đổi tên phương thức làm thay đổi đối số của phương thức

Đây là một trong những lớn trong tâm trí của tôi. Đây là lý do mà phương pháp tiêu chuẩn không nên được thực hiện. Bạn đang thay đổi các đối số được truyền cho việc triển khai phương thức ban đầu. Đây là nơi nó xảy ra:

[self my_setFrame:frame];

Những gì dòng này làm là:

objc_msgSend(self, @selector(my_setFrame:), frame);

Mà sẽ sử dụng thời gian chạy để tra cứu việc thực hiện my_setFrame:. Sau khi thực hiện được tìm thấy, nó gọi thực hiện với cùng các đối số đã được đưa ra. Việc triển khai mà nó tìm thấy là việc thực hiện ban đầu setFrame:, vì vậy nó đi trước và gọi điều đó, nhưng _cmdđối số không setFrame:giống như vậy. Bây giờ là bây giờ my_setFrame:. Việc thực hiện ban đầu đang được gọi với một đối số mà nó không bao giờ mong đợi nó sẽ nhận được. Điều này là không tốt.

Có một giải pháp đơn giản - sử dụng kỹ thuật thay thế thay thế được xác định ở trên. Các đối số sẽ không thay đổi!

Thứ tự của các vấn đề

Thứ tự trong đó các phương pháp có được vấn đề swizzled. Giả địnhsetFrame: chỉ được định nghĩa trên NSView, hãy tưởng tượng thứ tự này:

[NSButton swizzle:@selector(setFrame:) with:@selector(my_buttonSetFrame:)];
[NSControl swizzle:@selector(setFrame:) with:@selector(my_controlSetFrame:)];
[NSView swizzle:@selector(setFrame:) with:@selector(my_viewSetFrame:)];

Điều gì xảy ra khi phương thức trên NSButtonbị xáo trộn? Hầu hết các sự thay đổi sẽ đảm bảo rằng nó không thay thế việc thực hiện setFrame:cho tất cả các chế độ xem, vì vậy nó sẽ mở ra phương thức cá thể. Điều này sẽ sử dụng triển khai hiện có để xác định lại setFrame:trongNSButton lớp để việc thực hiện trao đổi không ảnh hưởng đến tất cả các khung nhìn. Việc thực hiện hiện tại là một trong những định nghĩa trên NSView. Điều tương tự sẽ xảy ra khi bật lên NSControl(một lần nữa sử dụng NSViewthực hiện).

Do đó, khi bạn gọi setFrame:vào một nút, nó sẽ gọi phương thức bị xáo trộn của bạn, và sau đó nhảy thẳng đến setFrame:phương thức được xác định ban đầu NSView. Các triển khai NSControlNSViewswizzled sẽ không được gọi.

Nhưng nếu thứ tự là:

[NSView swizzle:@selector(setFrame:) with:@selector(my_viewSetFrame:)];
[NSControl swizzle:@selector(setFrame:) with:@selector(my_controlSetFrame:)];
[NSButton swizzle:@selector(setFrame:) with:@selector(my_buttonSetFrame:)];

Kể từ khi chế độ xem xáo trộn diễn ra trước tiên, điều khiển phồng sẽ có thể kéo lên đúng phương pháp. Tương tự như vậy, vì điều khiển bị phồng lên trước khi nút bị phồng lên, nút sẽ kéo lên việc thực hiện bị trượt của điều khiển setFrame:. Điều này hơi khó hiểu, nhưng đây là thứ tự chính xác. Làm thế nào chúng ta có thể đảm bảo thứ tự này của mọi thứ?

Một lần nữa, chỉ cần sử dụng load để làm xáo trộn mọi thứ. Nếu bạn lướt qua loadvà bạn chỉ thực hiện thay đổi cho lớp đang được tải, bạn sẽ an toàn. Các loadđảm bảo phương pháp mà các siêu phương pháp nạp lớp sẽ được gọi trước khi bất kỳ lớp con. Chúng tôi sẽ nhận được thứ tự chính xác!

Khó hiểu (có vẻ đệ quy)

Nhìn vào một phương pháp xáo trộn được xác định theo truyền thống, tôi nghĩ thật khó để biết chuyện gì đang xảy ra. Nhưng nhìn vào cách khác mà chúng ta đã thực hiện ở trên, điều đó thật dễ hiểu. Điều này đã được giải quyết!

Khó gỡ lỗi

Một trong những nhầm lẫn trong quá trình gỡ lỗi là nhìn thấy một khoảng lùi kỳ lạ nơi các tên bị xáo trộn được trộn lẫn và mọi thứ bị xáo trộn trong đầu bạn. Một lần nữa, việc thực hiện thay thế giải quyết điều này. Bạn sẽ thấy các chức năng được đặt tên rõ ràng trong backtraces. Tuy nhiên, swizzling có thể khó gỡ lỗi vì thật khó để nhớ những gì tác động của swizzling đang có. Tài liệu mã của bạn tốt (ngay cả khi bạn nghĩ bạn là người duy nhất sẽ nhìn thấy nó). Thực hiện theo các thực hành tốt, và bạn sẽ ổn thôi. Nó không khó để gỡ lỗi hơn mã đa luồng.

Phần kết luận

Phương pháp swizzling là an toàn nếu sử dụng đúng cách. Một biện pháp an toàn đơn giản bạn có thể thực hiện là chỉ lướt qua load. Giống như nhiều thứ trong lập trình, nó có thể nguy hiểm, nhưng hiểu được hậu quả sẽ cho phép bạn sử dụng nó đúng cách.


1 Sử dụng phương pháp làm mờ được xác định ở trên, bạn có thể làm cho mọi thứ trở nên an toàn nếu bạn sử dụng trampolines. Bạn sẽ cần hai tấm bạt lò xo. Khi bắt đầu phương thức, bạn sẽ phải gán con trỏ hàm store, cho một hàm quay cho đến khi địa chỉ được storetrỏ đến thay đổi. Điều này sẽ tránh mọi điều kiện cuộc đua trong đó phương thức bị xáo trộn được gọi trước khi bạn có thể đặt storecon trỏ hàm. Sau đó, bạn sẽ cần sử dụng một tấm bạt lò xo trong trường hợp việc triển khai chưa được xác định trong lớp và có tra cứu tấm bạt lò xo và gọi phương thức siêu hạng đúng cách. Xác định phương thức để nó tự động tra cứu siêu triển khai sẽ đảm bảo rằng thứ tự các cuộc gọi bị trượt không thành vấn đề.


24
Tuyệt vời thông tin và kỹ thuật trả lời âm thanh. Các cuộc thảo luận là thực sự thú vị. Cảm ơn đã dành thời gian để viết những dòng này.
Ricardo Sanchez-Saez

Bạn có thể chỉ ra nếu trải nghiệm của bạn trong các cửa hàng ứng dụng. Tôi cũng đang hướng dẫn bạn đến stackoverflow.com/questions/8834294 .
Dickey Singh

3
Swizzling có thể được sử dụng trên App store. Nhiều ứng dụng và khung làm (bao gồm cả chúng tôi). Tất cả mọi thứ ở trên vẫn giữ và bạn không thể làm mờ các phương thức riêng tư (thực ra, về mặt kỹ thuật bạn có thể, nhưng bạn sẽ có nguy cơ từ chối và những nguy hiểm của việc này là đối với một luồng khác).
wbyoung

Câu trả lời tuyệt vời. Nhưng tại sao làm cho swizzling trong class_swizzleMethodAndStore () thay vì trực tiếp trong + swizzle: với: store:? Tại sao chức năng bổ sung này?
Frizlab

2
@Frizlab câu hỏi hay! Nó thực sự chỉ là một phong cách. Nếu bạn đang viết một loạt mã hoạt động trực tiếp với API thời gian chạy Objective-C (bằng C), thì thật tuyệt khi có thể gọi nó là kiểu C để thống nhất. Lý do duy nhất tôi có thể nghĩ đến bên cạnh điều này là nếu bạn đã viết một cái gì đó bằng chữ C thuần túy, thì nó vẫn còn dễ gọi hơn. Dù vậy, không có lý do gì bạn không thể làm tất cả trong phương pháp Objective-C.
wbyoung

12

Đầu tiên tôi sẽ xác định chính xác những gì tôi muốn nói bằng phương pháp swizzling:

  • Định tuyến lại tất cả các cuộc gọi ban đầu được gửi đến một phương thức (được gọi là A) đến một phương thức mới (được gọi là B).
  • Chúng tôi sở hữu Phương pháp B
  • Chúng tôi không sở hữu phương pháp A
  • Phương thức B thực hiện một số công việc sau đó gọi phương thức A.

Phương pháp swizzling là tổng quát hơn thế này, nhưng đây là trường hợp tôi quan tâm.

Nguy hiểm

  • Thay đổi trong lớp ban đầu . Chúng tôi không sở hữu lớp học mà chúng tôi đang nổi. Nếu lớp thay đổi, swizzle của chúng tôi có thể ngừng hoạt động.

  • Khó bảo trì . Bạn không chỉ phải viết và duy trì phương pháp thay đổi. bạn phải viết và duy trì mã tạo ra sự thay đổi

  • Khó gỡ lỗi . Thật khó để theo dòng chảy của một cơn lốc, một số người thậm chí có thể không nhận ra sự thay đổi đã được tạo hình sẵn. Nếu có lỗi được giới thiệu từ swizzle (có lẽ là thay đổi trong lớp gốc), chúng sẽ khó giải quyết.

Tóm lại, bạn nên tiếp tục giảm đến mức tối thiểu và xem xét những thay đổi trong lớp ban đầu có thể ảnh hưởng đến sự thay đổi của bạn như thế nào. Ngoài ra, bạn nên bình luận rõ ràng và ghi lại những gì bạn đang làm (hoặc chỉ cần tránh hoàn toàn).


@everyone Tôi đã kết hợp câu trả lời của bạn thành một định dạng đẹp. Hãy chỉnh sửa / thêm vào nó. Cảm ơn vì đầu vào của bạn.
Robert

Tôi là một fan hâm mộ của tâm lý của bạn. "Với sức mạnh lớn lao đến trách nhiệm phù hợp lớn."
Jacksonkr

7

Đó không phải là sự phồng lên mà thực sự nguy hiểm. Vấn đề là, như bạn nói, nó thường được sử dụng để sửa đổi hành vi của các lớp khung. Giả sử rằng bạn biết điều gì đó về cách các lớp tư nhân đó hoạt động "nguy hiểm". Ngay cả khi các sửa đổi của bạn hoạt động ngày hôm nay, luôn có cơ hội Apple sẽ thay đổi lớp trong tương lai và khiến sửa đổi của bạn bị phá vỡ. Ngoài ra, nếu nhiều ứng dụng khác nhau làm điều đó, điều đó khiến Apple khó thay đổi khuôn khổ hơn mà không phá vỡ nhiều phần mềm hiện có.


Tôi muốn nói rằng các Dev như vậy sẽ gặt hái những gì họ gieo - họ kết hợp chặt chẽ mã của họ với một triển khai cụ thể. Do đó, đó là lỗi của họ nếu việc triển khai đó thay đổi một cách tinh vi không nên phá vỡ mã của họ nếu đó không phải là quyết định rõ ràng của họ để ghép mã của họ chặt chẽ như họ đã làm.
Arafangion

Chắc chắn, nhưng nói rằng một ứng dụng rất phổ biến phá vỡ dưới phiên bản tiếp theo của iOS. Thật dễ dàng để nói rằng đó là lỗi của nhà phát triển và họ nên biết rõ hơn, nhưng điều đó làm cho Apple trông tệ trong mắt người dùng. Tôi không thấy bất kỳ tác hại nào trong việc làm mờ các phương thức của riêng bạn hoặc thậm chí các lớp nếu bạn muốn làm điều đó, ngoài quan điểm của bạn rằng nó có thể làm cho mã hơi khó hiểu. Nó bắt đầu trở nên rủi ro hơn một chút khi bạn viết mã bị điều khiển bởi người khác - và đó chính xác là tình huống mà sự phồng lên có vẻ hấp dẫn nhất.
Caleb

Apple không phải là nhà cung cấp duy nhất các lớp cơ sở có thể được sửa đổi thông qua siwzzling. Câu trả lời của bạn nên được chỉnh sửa để bao gồm tất cả mọi người.
AR

@AR Có lẽ, nhưng câu hỏi được gắn thẻ iOS và iPhone, vì vậy chúng ta nên xem xét nó trong bối cảnh đó. Do các ứng dụng iOS phải liên kết tĩnh bất kỳ thư viện và khung nào ngoài các thư viện do iOS cung cấp, Apple thực tế là thực thể duy nhất có thể thay đổi việc triển khai các lớp khung mà không có sự tham gia của các nhà phát triển ứng dụng. Nhưng tôi đồng ý với quan điểm rằng các vấn đề tương tự ảnh hưởng đến các nền tảng khác và tôi nói rằng lời khuyên có thể được khái quát hóa vượt ra ngoài sự phù hợp. Ở dạng chung, lời khuyên là: Giữ tay bạn. Tránh sửa đổi các thành phần mà người khác duy trì.
Caleb

Phương pháp swizzling có thể là nguy hiểm. nhưng khi các khung xuất hiện, họ không hoàn toàn bỏ qua các khung trước đó. bạn vẫn phải cập nhật khung cơ sở mà ứng dụng của bạn mong đợi. và bản cập nhật đó sẽ phá vỡ ứng dụng của bạn. nó có thể không phải là một vấn đề lớn khi ios được cập nhật. Mẫu sử dụng của tôi là ghi đè lên reuseIdentifier mặc định. Vì tôi không có quyền truy cập vào biến _reuseIdentifier và không muốn thay thế nó trừ khi nó không được cung cấp, giải pháp duy nhất của tôi là phân lớp mỗi cái và cung cấp định danh tái sử dụng, hoặc làm mờ và ghi đè nếu không. Kiểu triển khai là chính ...
Bộ giải mã lười biếng

5

Được sử dụng cẩn thận và khôn ngoan, nó có thể dẫn đến mã thanh lịch, nhưng thông thường, nó chỉ dẫn đến mã khó hiểu.

Tôi nói rằng nó nên bị cấm, trừ khi bạn tình cờ biết rằng nó mang lại cơ hội rất thanh lịch cho một nhiệm vụ thiết kế cụ thể, nhưng bạn cần biết rõ lý do tại sao nó áp dụng tốt cho tình huống và tại sao các giải pháp thay thế không hoạt động tốt cho tình huống .

Ví dụ, một ứng dụng hay của phương pháp swizzling là isa swizzling, đó là cách ObjC thực hiện Quan sát giá trị chính.

Một ví dụ tồi tệ có thể dựa vào phương pháp phồng lên như một phương tiện để mở rộng các lớp học của bạn, dẫn đến khả năng ghép nối cực cao.


1
-1 cho đề cập đến KVO trong bối cảnh phương pháp phình ra . isa swizzling chỉ là một cái gì đó khác.
Nikolai Ruhe

@NikolaiRuhe: Xin vui lòng cung cấp tài liệu tham khảo để tôi có thể được giác ngộ.
Arafangion

Đây là một tham chiếu đến các chi tiết thực hiện của KVO . Phương pháp swizzling được mô tả trên CocoaDev.
Nikolai Ruhe

5

Mặc dù tôi đã sử dụng kỹ thuật này, tôi muốn chỉ ra rằng:

  • Nó làm xáo trộn mã của bạn bởi vì nó có thể gây ra các tác dụng phụ không được ghi lại, mặc dù mong muốn. Khi một người đọc mã, anh ấy / cô ấy có thể không biết về hành vi tác dụng phụ được yêu cầu trừ khi anh ấy / cô ấy nhớ tìm kiếm cơ sở mã để xem liệu nó có bị xáo trộn không. Tôi không chắc làm thế nào để giảm bớt vấn đề này bởi vì không phải lúc nào cũng có thể ghi lại mọi nơi mà mã phụ thuộc vào tác dụng phụ bị thay đổi.
  • Nó có thể làm cho mã của bạn ít sử dụng lại được bởi vì ai đó tìm thấy một đoạn mã phụ thuộc vào hành vi bị xáo trộn mà họ muốn sử dụng ở nơi khác không thể đơn giản cắt và dán mã vào một số cơ sở mã khác mà không cần tìm và sao chép phương thức bị xáo trộn.

4

Tôi cảm thấy rằng mối nguy hiểm lớn nhất là tạo ra nhiều tác dụng phụ không mong muốn, hoàn toàn do tai nạn. Những tác dụng phụ này có thể tự hiện là "lỗi", từ đó dẫn bạn đi sai đường để tìm giải pháp. Theo kinh nghiệm của tôi, sự nguy hiểm là mã bất khả thi, khó hiểu và bực bội. Kiểu như khi ai đó lạm dụng các con trỏ hàm trong C ++.


Ok, vì vậy vấn đề là rất khó để gỡ lỗi. Các vấn đề được gây ra bởi vì các nhà đánh giá không nhận ra / quên rằng mã đã bị xáo trộn và đang tìm sai vị trí khi gỡ lỗi.
Robert

3
Có khá nhiều. Ngoài ra, khi sử dụng quá mức, bạn có thể vào một chuỗi vô tận hoặc các trang web của swizzles. Hãy tưởng tượng những gì có thể xảy ra khi bạn thay đổi chỉ một trong số chúng tại tương lai? Tôi thích trải nghiệm xếp chồng tách trà hoặc chơi 'code jenga'
AR

4

Bạn có thể kết thúc với mã tìm kiếm kỳ lạ như

- (void)addSubview:(UIView *)view atIndex:(NSInteger)index {
    //this looks like an infinite loop but we're swizzling so default will get called
    [self addSubview:view atIndex:index];

từ mã sản xuất thực tế liên quan đến một số phép thuật UI.


3

Phương pháp swizzling có thể rất hữu ích là trong thử nghiệm đơn vị.

Nó cho phép bạn viết một đối tượng giả và sử dụng đối tượng giả đó thay vì đối tượng thực. Mã của bạn vẫn sạch và kiểm tra đơn vị của bạn có hành vi dự đoán. Giả sử bạn muốn kiểm tra một số mã sử dụng CLLocationManager. Kiểm tra đơn vị của bạn có thể làm thay đổi startUpdatingLocation để nó cung cấp một tập hợp các vị trí được xác định trước cho đại biểu của bạn và mã của bạn sẽ không phải thay đổi.


isa-swizzling sẽ là một lựa chọn tốt hơn.
vikingosegundo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.