Xcode omitting parameters names of block - ios

I have a block property that looks like this:
#property (nonatomic, copy) void (^indexChangeBlock)(NSInteger index);
When I try to set the value for this property, Xcode autocomplete will omit the parameter name leaving me with something like this:
[self.segmentedControl3 setIndexChangeBlock:^(NSInteger) {
code
}];
Then Xcode shows a Parameter name omitted error. I'm aware that I can solve this by adding the parameter name manually to make it look like this:
[self.segmentedControl3 setIndexChangeBlock:^(NSInteger index) {
code
}];
My questions is, how can I make Xcode add the parameters names automatically. Or in other words, prevent it from removing them.

possible solution:
typedef void (^IndexChangeBlock)(NSInteger index);
and define your property with
#property (nonatomic, copy) IndexChangeBlock indexChangeBlock;
and if you add
- (void)setIndexChangeBlock:(IndexChangeBlock)indexChangeBlock;
everything should work

In exacerbated frustration, I made a macro consolidating this gross process..
#define BlockProperty(SIGNATURE,TYPENAME,varname,Varname) typedef SIGNATURE; #property (nonatomic,copy) TYPENAME varname; - (void) set##Varname:(TYPENAME)_
Now what Previously would've required (for proper autocompletion)..
typedef void(^OnEvent)(BOOL ok,id result);
#property (nonatomic,copy) OnEvent varname;
- (void) setVarname:(OnEvent)_;
is simply
BlockProperty(void(^OnEvent)(BOOL ok, id result),OnEvent,varname,VarName);
QUITE a bit easier, less verbose, AND you get the benefit of the typedef AND and you don't have to create the unsightly, theoretically unneeded setter declaration!
If you WANT to reuse a "type" you'll need another one (which this time will only take THREE parameters (as the block type cannot be redeclared).
#define BlockProp(TYPENAME,varname,Varname) #property (nonatomic,copy) TYPENAME varname; - (void) set##Varname:(TYPENAME)_
BlockProp(OnEvent,anotherVar,AnotherVar);
You could just create a new block type (name) for each property even if their signatures match (using the first macro), but that's kind of gross. Enjoy!

Related

ARC unavailable methods in Swift

I was able to see an interesting case using
Estimote nearables SDK
They have a class ESTNearable with property called zone.
// ENUM
typedef NS_ENUM(NSInteger, ESTNearableZone ) {
ESTNearableZoneUnknown = 0,
ESTNearableZoneImmediate,
ESTNearableZoneNear,
ESTNearableZoneFar,
};
// CLASS
#interface ESTNearable : NSObject <NSCopying, NSCoding>
// ...
#property (nonatomic, assign, readonly) ESTNearableZone zone;
// ...
#end
So when I try to use this method in Swift, compiler fails with that error:
As I understand there is some kind of compiler bug and for some reason it believes that I want to use old zone method from NSObject - (struct _NSZone *)zone OBJC_ARC_UNAVAILABLE; I can use other specific properties of that class without any problems.
As I use an SDK I can not change the name of the zone method. I believe I can write some kind of obj-c category, add some new method there, which will return value of original one, but I do not want to add obj-c classes in my project.
Is there any possibility to call this method from swift as I believe correct zone method will be called for class instances?
Thanks in advance!
Here I found the same question. I answered more deeply there. I could not find something more good, so I went ahead with my old assumptions.
I Added this category to Bridging Header. It worked fine.
#import <EstimoteSDK/EstimoteSDK.h>
#interface ESTNearable (Ex)
/// Solving the compiler problem that "zone" method is unavailable in Swift
#property (readonly) ESTNearableZone nearableZone;
#end
// Implementation
#implementation ESTNearable (Ex)
- (ESTNearableZone)nearableZone
{
return self.zone;
}
#end
After that I just used nearableZone method in Swift
var zone = someNearable.nearableZone

Reassigning deprecated properties to new properties objective-c

I've got a property that I want to change the name of. Basically I want the old property to return/set the value of the new property so existing code doesn't break, but it'll throw warnings to use the new name.
This is in my header file:
#property (nonatomic, strong) MyClass *newProperty;
#property (nonatomic, strong) MyClass *oldProperty __attribute__((deprecated));
To make oldProperty's getters and setters just set/return newProperty's values in the implementation i'd like to do something like
#synthesize oldProperty=_newProperty;
This throws an error 'oldProperty and newProperty both claim instance variable _newProperty'. Whats the best way to achieve what I want to do? (I'm deprecating and renaming about 30 properties)
Setting the getters/setters manually returns the same error
- (void)setOldProperty:(MyClass *)oldProperty {
_newProperty=oldProperty;
}
- (MyClass *)oldProperty:(MyClass *)oldProperty {
return _newProperty;
}
EDIT: Solution I used with the help of BlackRiders input -------------------------------------------------------------
Interface:
#property (nonatomic, strong) MyClass *newProperty;
- (void)setOldProperty:(MyClass *)oldProperty __attribute__((deprecated));
- (MyClass *)oldProperty __attribute__((deprecated));
Implementation:
- (void)setOldProperty:(MyClass *)oldProperty {
_newProperty=oldProperty;
}
- (MyClass *)oldProperty {
return _newProperty;
}
I would have just one actual property to avoid confusion and name collisions. For example:
property (getter=oldProperty, setter=setOldProperty:) MyClass *newProperty;
You can also optionally create the methods newProperty and setNewProperty:. You can also throw in some #warning statements in the getter and setter you want people to stop using.

How to get the correct autocomplete in XCode for a block variable?

I have a block thats stored as an instance variable in a class
typedef void ((^didSelectWord)(NSString* word));
#property (nonatomic,strong) didSelectWord wordSelected;
and i want xcode to auto fillout the block like when you type [UIView animateWithDuration and xcode autocompletes a block for it.
When i autocomplete my block it just fills out
[self.suggestedSearchTermView setWordSelected:(didSelectWord)wordSelected
instead of
[self.suggestedSearchTermView setWordSelected:^(NSString *word) {
Is it possible to change something to make Xcode understand how to autocomplete this block?
Ok I did some testing.
Apparently you have two (far from perfect) options:
avoid the typedef and declare the property as
#property (nonatomic,strong) void (^wordSelected)(NSString * word);
As noted in the comments, this has the drawback of skipping the parameter name in the autocompletion.
explicitly add a setter declaration in the interface
typedef void ((^DidSelectWordBlock)(NSString* word));
#interface YourClass : NSObject
#property (nonatomic,strong) DidSelectWordBlock wordSelected;
- (void)setWordSelected:(DidSelectWordBlock)wordSelected;
#end
this will cause Xcode to resolve the type definition before the setter definition, giving you the nice autocompletion that you would expect. The obvious drawback is the extra setter declaration in the interface.
That said, you should fill in a bug report: http://openradar.appspot.com/
Declare your property without typedef, like this:
#property (nonatomic,strong) void (^wordSelected)(NSString *word);
With this definition Xcode would give you the expansion below:
MyClass *test = [MyClass new];
[test setWordSelected:(void (^)(NSString *))wordSelected];
In exacerbated frustration, I made a macro consolidating this gross process..
#define BlockProperty(SIGNATURE,TYPENAME,varname,Varname) typedef SIGNATURE; #property (nonatomic,copy) TYPENAME varname; - (void) set##Varname:(TYPENAME)_
Now what Previously would've required (for proper autocompletion)..
typedef void(^OnEvent)(BOOL ok,id result);
#property (nonatomic,copy) OnEvent varname;
- (void) setVarname:(OnEvent)_;
is simply
BlockProperty(void(^OnEvent)(BOOL ok, id result),OnEvent,varname,VarName);
QUITE a bit easier, less verbose, AND you get the benefit of the typedef AND and you don't have to create the unsightly, theoretically unneeded setter declaration!
If you WANT to reuse a "type" you'll need another one (which this time will only take THREE parameters (as the block type cannot be redeclared).
#define BlockProp(TYPENAME,varname,Varname) #property (nonatomic,copy) TYPENAME varname; - (void) set##Varname:(TYPENAME)_
BlockProp(OnEvent,anotherVar,AnotherVar);
You could just create a new block type (name) for each property even if their signatures match (using the first macro), but that's kind of gross. Enjoy!

Please help me with block-based callbacks

I have an ill-understanding of block-based callbacks. There seems to be two approaches that I'm aware of and I don't know when I should be using one over the other so could someone please explain to me the differences between the two, correct me and give me some tips if I need any.
Some code I found off stackoverflow as well as a library from elsewhere so thanks to those who wrote this code.
typedef void (^MyClickedIndexBlock)(NSInteger index);
#interface YourInterface : YourSuperClass
#property (nonatomic, strong) MyClickedIndexBlock clickedIndexBlock
.m
//where you have to call the block
if (self.clickedIndexBlock != nil) {self.clickedIndexBlock(buttonIndex)};
// where you want to receive the callback
alert.clickedIndexBlock = ^(NSInteger index){NSLog(#"%d", index);};
my understanding with the above is that:
MyClickedIndexBlock is typedef to a NSInteger. Property created with the name "clickedIndexBlock" which is of type MyClickedIndexBlock (meaning that clickedIndexBlock can be a number).
Blocks can also be used as methods which is why I can call self.clickedIndexBlock(buttonIndex);
BUT something tells me that this approach as a #property only really supports one parameter
eg. NSInteger.
WHEREAS the following approach allows for more than one parameter.
bluetoothMe.h
typedef void (^hardwareStatusBlock)(CBPeripheral *peripheral, BLUETOOTH_STATUS status, NSError *error);
- (void)hardwareResponse:(hardwareStatusBlock)block;
bluetoothMe.m
- (void)hardwareResponse:(hardwareStatusBlock)block {
privateBlock = [block copy];
}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
NSLog(#"Did connect to peripheral: %#", peripheral);
privateBlock(peripheral, BLUETOOTH_STATUS_CONNECTED, nil);
NSLog(#"Connected");
[peripheral setDelegate:self];
[peripheral discoverServices:nil];
}
My understanding that creating a property which is strong and doing a [block copy] will retain the block around until the app terminates. So [block copy] and strong both retain. [block copy] is applied to the block to retain otherwise the block would have vanished when the method goes out of scope.
ViewController.m
[instance hardwareResponse:^(CBPeripheral *peripheral, BLUETOOTH_STATUS status, NSError *error) {
if (status == BLUETOOTH_STATUS_CONNECTED)
{
NSLog(#"connected!");
}
else if (status == BLUETOOTH_STATUS_FAIL_TO_CONNECT)
{
NSLog(#"fail to connect!");
}
else
{
NSLog(#"disconnected!");
}
NSLog(#"CBUUID: %#, ERROR: %#", (NSString *)peripheral.UUID, error.localizedDescription);
}];
So lets see what my questions were:
1) When would I choose the first approach over the second approach and vice versa?
2) First example, the block was a typedef to a property. Second example, the block was declared a method. Why couldn't the first example be declared a method and why couldn'tt the second example be typedef to a property?
3) Would I need to create a typedef for every type of delegate method that I want a block-based callback for?
4) At of date, ive only seen one delegate method supported. Could you show me an example on how one would implement each approach if I was to create block-based callbacks on multiple delegate methods which are not similar.
Appreciate your feedback. This is hard at times. Need as much help as I can get.
Thanks,
Ben
The questions
Whether to typedef a block or not,
whether to use a property for a block or not,
whether a block has a single or multiple arguments,
are completely independent (or orthogonal). All combinations are
possible and allowed.
void (^myClickedIndexBlock)(NSInteger index);
declares a block variable myClickedIndexBlock taking an integer argument
and returning void. You can use typedef if the same block type occurs
repeatedly in your program:
// Define MyClickedIndexBlock as *type* of a block taking an integer argument and returning void:
typedef void (^MyClickedIndexBlock)(NSInteger index);
// Declare myClickedIndexBlock as a *variable* of that type:
MyClickedIndexBlock myClickedIndexBlock;
With multiple arguments:
void (^privateBlock)(CBPeripheral *peripheral, BLUETOOTH_STATUS status, NSError *error);
or
typedef void (^hardwareStatusBlock)(CBPeripheral *peripheral, BLUETOOTH_STATUS status, NSError *error);
hardwareStatusBlock privateBlock;
Instead of (instance) variables, you can use properties. In the first example:
#property (nonatomic, copy) void (^myClickedIndexBlock)(NSInteger index);
declares myClickedIndexBlock as a block property, and is equivalent to
typedef void (^MyClickedIndexBlock)(NSInteger index);
#property (nonatomic, copy) MyClickedIndexBlock clickedIndexBlock;
Contrary to your assumption, block properties are not restricted to blocks
with a single argument. You can use a property also in the second example,
with or without typedef:
#property (nonatomic, copy) void (^privateBlock)(CBPeripheral *peripheral, BLUETOOTH_STATUS status, NSError *error);
or
typedef void (^hardwareStatusBlock)(CBPeripheral *peripheral, BLUETOOTH_STATUS status, NSError *error);
#property (nonatomic, copy) privateBlock;
It is your choice whether to use instance variables or properties for blocks.
I would use properties (with the "copy" attribute).
Whether to typedef or not is purely a matter of taste. It helps to avoid
errors if the same block type occurs repeatedly in your program. On the other
hand, the Xcode autocompletion seems to work better without typedef (in my
experience).
I strongly suggest you read the Blocks Programming Guide.
Blocks are not methods. I'm not going to paraphrase what's said in the Conceptual Overview, but just quote some parts:
Blocks represent typically small, self-contained pieces of code. [...]
They allow you to write code at the point of invocation that is executed later in the context of the method implementation.
It seems you're confused by the syntax.
typedef void (^MyClickedIndexBlock)(NSInteger index);
It's basically just defining a type named MyClickedIndexBlock representing a block that takes a single parameter of type NSInteger and returns nothing (void).
It's not a typedef to a NSInteger.
#property (nonatomic, strong) MyClickedIndexBlock clickedIndexBlock
is a declaration of a property that will contain a MyClickedIndexBlock.
It's not required to typedef blocks, it would be perfectly valid to write
#property (nonatomic, strong) void(^clickedIndexBlock)(NSInteger index);
But for the sake of clarity (or reuse), you may choose to typedef them. Notice that the property name is what follows the ^.
You're stating that blocks can be used as methods because it's possible to call self.clickedIndexBlock(buttonIndex) in your example. But in fact, it's because you've declared a property named clickedIndexBlock that you can call it like that.
There's a lot in your question, but a large part is due to confusion and misunderstanding. The 2 approaches you mention aren't really different. Blocks are objects and can be manipulated as parameters, local variables or ivars / properties just as you would do with NSString or other kinds of objects.
1) The block isn't typedef'd to an integer. It's typedef'd to return void and has an integer parameter. There is no advantage to ethos 1 or method 2; they both can have multiple parameters if declared.
2) No reason why that format has been chosen for either case. They both achieve the same result, but the first one is arguably better semantically.
3) No. You can declare blocks inline to a method. Look at the header for [NSArray enumerateObjectsUsingBlock:] for an example of inline block declaration.
4) You can just create multiple properties and call each distinct block when necessary.

property not found on object Type (custom) xcode

the strangest thing happened. Although I don't think I touched anything in that class, suddenly it started telling me it couldn't find an array in a class...
Here are the errors:
basically it cannot access the mutable array in baseobject (custom Car.h type)
(semantic issue: property objectReadyForCoreDatabase not found in object of type CarPacket (false, because it is declared))
if([baseObject.objectsReadyForCoreDataBaseInput count]<kLenght )
{
}
car packet .h
#import <Foundation/Foundation.h>
#import "ResponsePacket.h"
#interface CarPacket : ResponsePacket
#property (nonatomic, copy) NSString *objectID;
#property (nonatomic, retain) NSMutableArray *objectsReadyForCoreDataBaseInput;
#property (nonatomic, assign) NSInteger timeStamp;
#end
It is weird because on the same page where I get the error if I type object.objectID it recognizes that but not object.objectReadyForCoreDataBaseInput (also it just suddenly stopped working)
Please let me know if you have any ideas... Thank you
I tried restoring to previous snapshots and it had no effect... it still showed the error (even though I know on that date it didn't)
You haven't shared much about the context of where you're making the call (and seeing the error). That said, my guess would be one of two things: The calling class isn't familiar with the receiving class (CarPacket), or, the calling class doesn't know that baseObject is a CarPacket.
Where are you calling from? Make sure the calling class imports the headers. Since I don't know where you're calling from, let's say it's from within UnknownClass:
UnknownClass.m
#import UnknownClass.h
#import CarPacket.h // This should make your class familiar
#implementation UnknownClass
The other thing is that you need to make sure that at the time you're touching the baseObject, your UnknownClass instance knows that it is dealing with a CarPacket instance, e.g.:
- (void)someMethodOfUnknownClass
{
CarPacket *baseObject = (CarPacket *)baseObject; // Cast baseObject if it hasn't been declared as a CarPack in scope...
if([baseObject.objectsReadyForCoreDataBaseInput count]<kLenght )
{
}
}

Resources