Có thể có các khối làm thuộc tính bằng cú pháp thuộc tính tiêu chuẩn không?
Có bất kỳ thay đổi cho ARC ?
Có thể có các khối làm thuộc tính bằng cú pháp thuộc tính tiêu chuẩn không?
Có bất kỳ thay đổi cho ARC ?
Câu trả lời:
@property (nonatomic, copy) void (^simpleBlock)(void);
@property (nonatomic, copy) BOOL (^blockWithParamter)(NSString *input);
Nếu bạn sẽ lặp lại cùng một khối ở một số nơi, hãy sử dụng loại def
typedef void(^MyCompletionBlock)(BOOL success, NSError *error);
@property (nonatomic) MyCompletionBlock completion;
@synthesize myProp = _myProp
@synthesize
mặc định là những gì bạn đang làm @synthesize name = _name;
stackoverflow.com/a/12119360/1052616
Đây là một ví dụ về cách bạn sẽ hoàn thành một nhiệm vụ như vậy:
#import <Foundation/Foundation.h>
typedef int (^IntBlock)();
@interface myobj : NSObject
{
IntBlock compare;
}
@property(readwrite, copy) IntBlock compare;
@end
@implementation myobj
@synthesize compare;
- (void)dealloc
{
// need to release the block since the property was declared copy. (for heap
// allocated blocks this prevents a potential leak, for compiler-optimized
// stack blocks it is a no-op)
// Note that for ARC, this is unnecessary, as with all properties, the memory management is handled for you.
[compare release];
[super dealloc];
}
@end
int main () {
@autoreleasepool {
myobj *ob = [[myobj alloc] init];
ob.compare = ^
{
return rand();
};
NSLog(@"%i", ob.compare());
// if not ARC
[ob release];
}
return 0;
}
Bây giờ, điều duy nhất cần thay đổi nếu bạn cần thay đổi kiểu so sánh sẽ là typedef int (^IntBlock)()
. Nếu bạn cần truyền hai đối tượng cho nó, hãy đổi nó thành: typedef int (^IntBlock)(id, id)
và thay đổi khối của bạn thành:
^ (id obj1, id obj2)
{
return rand();
};
Tôi hi vọng cái này giúp được.
EDIT ngày 12 tháng 3 năm 2012:
Đối với ARC, không có thay đổi cụ thể cần thiết, vì ARC sẽ quản lý các khối cho bạn miễn là chúng được xác định là bản sao. Bạn cũng không cần đặt thuộc tính thành số không trong hàm hủy của mình.
Để đọc thêm, vui lòng xem tài liệu này: http://clang.llvm.org/docs/AutomaticReferenceCounting.html
Đối với Swift, chỉ cần sử dụng bao đóng: ví dụ.
Trong Mục tiêu-C:
@property (copy)void (^doStuff)(void);
Nó đơn giản mà.
Trong tệp .h của bạn:
// Here is a block as a property:
//
// Someone passes you a block. You "hold on to it",
// while you do other stuff. Later, you use the block.
//
// The property 'doStuff' will hold the incoming block.
@property (copy)void (^doStuff)(void);
// Here's a method in your class.
// When someone CALLS this method, they PASS IN a block of code,
// which they want to be performed after the method is finished.
-(void)doSomethingAndThenDoThis:(void(^)(void))pleaseDoMeLater;
// We will hold on to that block of code in "doStuff".
Đây là tập tin .m của bạn:
-(void)doSomethingAndThenDoThis:(void(^)(void))pleaseDoMeLater
{
// Regarding the incoming block of code, save it for later:
self.doStuff = pleaseDoMeLater;
// Now do other processing, which could follow various paths,
// involve delays, and so on. Then after everything:
[self _alldone];
}
-(void)_alldone
{
NSLog(@"Processing finished, running the completion block.");
// Here's how to run the block:
if ( self.doStuff != nil )
self.doStuff();
}
Với các hệ thống hiện đại (2014+), hãy làm những gì được hiển thị ở đây. Nó là đơn giản.
strong
thay thế copy
không?
nonatomic
giống như thực tiễn tốt nhất cho hầu hết các trường hợp khác sử dụng tài sản không?
Vì lợi ích của hậu thế / sự hoàn thiện Đây là hai ví dụ ĐẦY ĐỦ về cách thực hiện "cách làm việc" linh hoạt kỳ cục này. Câu trả lời của @ Robert rất ngắn gọn và chính xác, nhưng ở đây tôi cũng muốn chỉ ra các cách để thực sự "định nghĩa" các khối.
@interface ReusableClass : NSObject
@property (nonatomic,copy) CALayer*(^layerFromArray)(NSArray*);
@end
@implementation ResusableClass
static NSString const * privateScope = @"Touch my monkey.";
- (CALayer*(^)(NSArray*)) layerFromArray {
return ^CALayer*(NSArray* array){
CALayer *returnLayer = CALayer.layer
for (id thing in array) {
[returnLayer doSomethingCrazy];
[returnLayer setValue:privateScope
forKey:@"anticsAndShenanigans"];
}
return list;
};
}
@end
Ngớ ngẩn? Đúng. Hữu ích? Địa ngục yeah. Đây là một cách khác nhau, "nguyên tử hơn" để thiết lập tài sản .. và một lớp có ích vô lý
@interface CALayoutDelegator : NSObject
@property (nonatomic,strong) void(^layoutBlock)(CALayer*);
@end
@implementation CALayoutDelegator
- (id) init {
return self = super.init ?
[self setLayoutBlock: ^(CALayer*layer){
for (CALayer* sub in layer.sublayers)
[sub someDefaultLayoutRoutine];
}], self : nil;
}
- (void) layoutSublayersOfLayer:(CALayer*)layer {
self.layoutBlock ? self.layoutBlock(layer) : nil;
}
@end
Điều này minh họa việc thiết lập thuộc tính khối thông qua trình truy cập (mặc dù bên trong init, một thực hành xúc xắc gây tranh cãi ..) so với cơ chế "getter" "không biến đổi" của ví dụ đầu tiên. Trong cả hai trường hợp, các triển khai "mã hóa cứng" luôn có thể được ghi đè, ví dụ .. một lá ..
CALayoutDelegator *littleHelper = CALayoutDelegator.new;
littleHelper.layoutBlock = ^(CALayer*layer){
[layer.sublayers do:^(id sub){ [sub somethingElseEntirely]; }];
};
someLayer.layoutManager = littleHelper;
Ngoài ra .. nếu bạn muốn thêm thuộc tính khối trong danh mục ... giả sử bạn muốn sử dụng Khối thay vì "hành động" mục tiêu / hành động cũ của trường học ... Bạn chỉ có thể sử dụng các giá trị được liên kết để, tốt .. liên kết các khối.
typedef void(^NSControlActionBlock)(NSControl*);
@interface NSControl (ActionBlocks)
@property (copy) NSControlActionBlock actionBlock; @end
@implementation NSControl (ActionBlocks)
- (NSControlActionBlock) actionBlock {
// use the "getter" method's selector to store/retrieve the block!
return objc_getAssociatedObject(self, _cmd);
}
- (void) setActionBlock:(NSControlActionBlock)ab {
objc_setAssociatedObject( // save (copy) the block associatively, as categories can't synthesize Ivars.
self, @selector(actionBlock),ab ,OBJC_ASSOCIATION_COPY);
self.target = self; // set self as target (where you call the block)
self.action = @selector(doItYourself); // this is where it's called.
}
- (void) doItYourself {
if (self.actionBlock && self.target == self) self.actionBlock(self);
}
@end
Bây giờ, khi bạn tạo một nút, bạn không cần phải thiết lập một số IBAction
bộ phim truyền hình .. Chỉ cần liên kết công việc sẽ được thực hiện khi tạo ...
_button.actionBlock = ^(NSControl*thisButton){
[doc open]; [thisButton setEnabled:NO];
};
Mẫu này có thể được áp dụng QUÁ và QUÁ cho API của Cacao. Sử dụng các thuộc tính để mang các phần có liên quan của mã của bạn lại gần nhau hơn , loại bỏ các mô hình ủy nhiệm phức tạp và tận dụng sức mạnh của các đối tượng vượt ra ngoài việc chỉ đóng vai trò là "các thùng chứa" câm.
Tất nhiên bạn có thể sử dụng các khối làm tài sản. Nhưng hãy chắc chắn rằng chúng được khai báo là @property (bản sao) . Ví dụ:
typedef void(^TestBlock)(void);
@interface SecondViewController : UIViewController
@property (nonatomic, copy) TestBlock block;
@end
Trong MRC, các khối bắt các biến bối cảnh được phân bổ trong ngăn xếp ; chúng sẽ được giải phóng khi khung stack bị phá hủy. Nếu chúng được sao chép, một khối mới sẽ được phân bổ thành từng đống , có thể được thực thi sau đó sau khi khung stack được bật lên.
Đây không phải là "câu trả lời tốt", vì câu hỏi này hỏi rõ ràng cho ObjectiveC. Như Apple đã giới thiệu Swift tại WWDC14, tôi muốn chia sẻ các cách khác nhau để sử dụng khối (hoặc đóng) trong Swift.
Bạn có nhiều cách được cung cấp để vượt qua một khối tương đương với chức năng trong Swift.
Tôi tìm thấy ba.
Để hiểu điều này, tôi khuyên bạn nên thử nghiệm trong sân chơi đoạn mã nhỏ này.
func test(function:String -> String) -> String
{
return function("test")
}
func funcStyle(s:String) -> String
{
return "FUNC__" + s + "__FUNC"
}
let resultFunc = test(funcStyle)
let blockStyle:(String) -> String = {s in return "BLOCK__" + s + "__BLOCK"}
let resultBlock = test(blockStyle)
let resultAnon = test({(s:String) -> String in return "ANON_" + s + "__ANON" })
println(resultFunc)
println(resultBlock)
println(resultAnon)
Vì Swift được tối ưu hóa để phát triển không đồng bộ, Apple đã làm việc nhiều hơn trong việc đóng cửa. Đầu tiên là chữ ký hàm có thể được suy ra để bạn không phải viết lại.
let resultShortAnon = test({return "ANON_" + $0 + "__ANON" })
let resultShortAnon2 = test({myParam in return "ANON_" + myParam + "__ANON" })
Trường hợp đặc biệt này chỉ hoạt động nếu khối là đối số cuối cùng, nó được gọi là đóng dấu
Dưới đây là một ví dụ (được hợp nhất với chữ ký được suy ra để thể hiện sức mạnh của Swift)
let resultTrailingClosure = test { return "TRAILCLOS_" + $0 + "__TRAILCLOS" }
Cuối cùng:
Sử dụng tất cả sức mạnh này, những gì tôi sẽ làm là trộn các lần đóng dấu và nhập suy luận (với cách đặt tên để dễ đọc)
PFFacebookUtils.logInWithPermissions(permissions) {
user, error in
if (!user) {
println("Uh oh. The user cancelled the Facebook login.")
} else if (user.isNew) {
println("User signed up and logged in through Facebook!")
} else {
println("User logged in through Facebook!")
}
}
Xin chào, Swift
Bổ sung những gì @Francescu đã trả lời.
Thêm tham số bổ sung:
func test(function:String -> String, param1:String, param2:String) -> String
{
return function("test"+param1 + param2)
}
func funcStyle(s:String) -> String
{
return "FUNC__" + s + "__FUNC"
}
let resultFunc = test(funcStyle, "parameter 1", "parameter 2")
let blockStyle:(String) -> String = {s in return "BLOCK__" + s + "__BLOCK"}
let resultBlock = test(blockStyle, "parameter 1", "parameter 2")
let resultAnon = test({(s:String) -> String in return "ANON_" + s + "__ANON" }, "parameter 1", "parameter 2")
println(resultFunc)
println(resultBlock)
println(resultAnon)
Bạn có thể làm theo định dạng dưới đây và có thể sử dụng thuộc testingObjectiveCBlock
tính trong lớp.
typedef void (^testingObjectiveCBlock)(NSString *errorMsg);
@interface MyClass : NSObject
@property (nonatomic, strong) testingObjectiveCBlock testingObjectiveCBlock;
@end
Để biết thêm thông tin có một cái nhìn ở đây