objc covariants implementation syntax - objective-c

#interface NSDictionary<__covariant KeyType, __covariant ObjectType>(String)
-(NSString*)stringForKey: (KeyType)key;
#end
#implementation NSDictionary(String)
-(NSString*)stringForKey: (KeyType)key;
^^^^^^^^ compiler says "Expected a type"
{
NSString *s = [self objectForKey:key];
if (![s isKindOfClass: [NSString class]]) {
s = nil; // guard against trash
}
return s;
}
#end
What's the proper syntax would be?
Thanks.

Related

Bad receiver type "Bool"

I have a problem with parsing with my server, specially the variable that I add. it doesn't let me to add it. the error message is "Bad receiver type "Bool"(aka "bool")"
here is my code :
#interface MessagingKeyServerResponse : NSObject <NSCopying>
#property (nonatomic, readonly) NSData *key;
#property (nonatomic, readonly) NSString *keyId;
#property (nonatomic, readonly) NSDate *validityStart;
#property (nonatomic, readonly) NSDate *validityEnd;
#property (nonatomic, readonly) BOOL support_long_messages;
#end
#interface MessagingKeyServerResponse ()
// added support_long_messages for parsing
-(instancetype)initWithKey:(NSData *)key keyId:(NSString *)keyId validityStart:(NSDate *)validityStart validityEnd:(NSDate *)validityEnd support_long_messages:(BOOL)support_long_messages;
#end
NS_ASSUME_NONNULL_END
#implementation MessagingKeyServerResponse
// steve note: added message long characters
-(instancetype)initWithKey:(NSData *)key keyId:(NSString *)keyId validityStart:(NSDate *)validityStart validityEnd:(NSDate *)validityEnd support_long_messages:(BOOL)support_long_messages
{
if (!key) {
[NSException raise:NSInvalidArgumentException format:#"No key"];
return nil;
}
if (!keyId) {
[NSException raise:NSInvalidArgumentException format:#"No key id"];
return nil;
}
if (!validityStart) {
[NSException raise:NSInvalidArgumentException format:#"No validity start"];
return nil;
}
if (!validityEnd) {
[NSException raise:NSInvalidArgumentException format:#"No validity end"];
return nil;
}
if (!support_long_messages) {
[NSException raise:NSInvalidArgumentException format:#"there is no support long Characters"];
return nil;
}
if (!([validityStart compare:validityEnd] == NSOrderedAscending)) {
[NSException raise:NSInvalidArgumentException format:#"Invalid validity range"];
return nil;
}
self = [super init];
if (self) {
_key = [key copy];
_keyId = [keyId copy];
_validityStart = [validityStart copy];
_validityEnd = [validityEnd copy];
_support_long_messages = [support_long_messages copy] ;
if (!_key || !_keyId || !_validityStart || !_validityEnd || !_support_long_messages) {
return nil;
}
}
return self;
}
so the error that I receive from _support_long_messages when I want to assign :
_support_long_messages = [support_long_messages copy] ;
any help appreciate.
Simply
_support_long_messages = support_long_messages;
BOOL is a value type, assignment already creates a copy.
Explicit copy is necessary only for reference types (objects).

How to implement chainable syntax with objective-c?

For example:
someObject.a.and.b.offset(5)
In objecitive-c, we know that a Class can have properties and methods, how to mix them to implement chainable syntax? How to design?
Have a look at this library: Underscore Library
Actually what it does it to return the same object you are operating on, so you can call more methods on the object (chaining them). Also block properties are used in order to obtain this syntax.
Here is an example from the website:
NSArray *tweets = Underscore.array(results)
// Let's make sure that we only operate on NSDictionaries, you never
// know with these APIs ;-)
.filter(Underscore.isDictionary)
// Remove all tweets that are in English
.reject(^BOOL (NSDictionary *tweet) {
return [tweet[#"iso_language_code"] isEqualToString:#"en"];
})
// Create a simple string representation for every tweet
.map(^NSString *(NSDictionary *tweet) {
NSString *name = tweet[#"from_user_name"];
NSString *text = tweet[#"text"];
return [NSString stringWithFormat:#"%#: %#", name, text];
})
.unwrap;
You might want to look at this SO-Thread aswell.
There is another library shown which implements this behaviour.
Here is my note. For example:
#class ClassB;
#interface ClassA : NSObject
//1. we define some the block properties
#property(nonatomic, readonly) ClassA *(^aaa)(BOOL enable);
#property(nonatomic, readonly) ClassA *(^bbb)(NSString* str);
#property(nonatomic, readonly) ClassB *(^ccc)(NSString* str);
#implement ClassA
//2. we implement these blocks, and remember the type of return value, it's important to chain next block
- (ClassA *(^)(BOOL))aaa
{
return ^(BOOL enable) {
//code
if (enable) {
NSLog(#"ClassA yes");
} else {
NSLog(#"ClassA no");
}
return self;
}
}
- (ClassA *(^)(NSString *))bbb
{
return ^(NSString *str)) {
//code
NSLog(#"%#", str);
return self;
}
}
// Here returns a instance which is kind of ClassB, then we can chain ClassB's block.
// See below .ccc(#"Objective-C").ddd(NO)
- (ClassB * (^)(NSString *))ccc
{
return ^(NSString *str) {
//code
NSLog(#"%#", str);
ClassB* b = [[ClassB alloc] initWithString:ccc];
return b;
}
}
//------------------------------------------
#interface ClassB : NSObject
#property(nonatomic, readonly) ClassB *(^ddd)(BOOL enable);
- (id)initWithString:(NSString *)str;
#implement ClassB
- (ClassB *(^)(BOOL))ddd
{
return ^(BOOL enable) {
//code
if (enable) {
NSLog(#"ClassB yes");
} else {
NSLog(#"ClassB no");
}
return self;
}
}
// At last, we can do it like this------------------------------------------
id a = [ClassA new];
a.aaa(YES).bbb(#"HelloWorld!").ccc(#"Objective-C").ddd(NO)

Duplicated custom object in NSSet

I have some problems about the NSMutableSet in Objective-C.
I learnt that the NSSet will compare the two objects' hash code to decide whether they are identical or not.
The problems is, I implemented a class that is subclass of NSObject myself. There is a property NSString *name in that class. What I want to do is when instances of this custom class has the same variable value of "name" , they should be identical, and such identical class should not be duplicated when adding to an NSMutableSet.
So I override the - (NSUInteger)hash function, and the debug shows it returns the same hash for my two instances obj1, obj2 (obj1.name == obj2.name). But when I added obj1, obj2 to an NSMutableSet, the NSMutableSet still contained both obj1, obj2 in it.
I tried two NSString which has the same value, then added them to NSMutableSet, the set will only be one NSString there.
What could be the solution? Thank you for any help!
The custom Class:
Object.h:
#import <Foundation/Foundation.h>
#interface Object : NSObject
#property (retain) NSString *name;
#end
Object.m
#implementation Object
#synthesize name;
-(BOOL)isEqualTo:(id)obj {
return [self.name isEqualToString:[(Object *)obj name]] ? true : false;
}
- (NSUInteger)hash {
return [[self name] hash];
}
#end
and main:
#import <Foundation/Foundation.h>
#import "Object.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
Object *obj1 = [[Object alloc]init];
Object *obj2 = [[Object alloc]init];
obj1.name = #"test";
obj2.name = #"test";
NSMutableSet *set = [[NSMutableSet alloc] initWithObjects:obj1, obj2, nil];
NSLog(#"%d", [obj1 isEqualTo:obj2]);
NSLog(#"%ld", [set count]);
}
return 0;
}
Instead of implementing isEqualTo: you have to implement isEqual:
- (BOOL)isEqual:(id)object {
return [object isKindOfClass:[MyObject class]] &&
[self.name isEqual:[(MyObject *)object name]];
}
This will (probably falsely) return NO if both self.name and object.name are nil. If you want to return YES if both properties are nil you should use
- (BOOL)isEqual:(id)object {
if ([object isKindOfClass:[MyObject class]]) {
return (!self.name && ![(MyObject *)object name]) ||
[self.name isEqual:[(MyObject *)object name]];
}
return NO;
}

Property not found on object of type error with method declaration in Objective C

Have a weird error on method declaration and call...
MyObject.h --- declarations. has been trimmed down
#import <Foundation/Foundation.h>
#interface MyObject : NSObject
- (void) useFlattenHTML;
- (NSString *) flattenHTML:(NSString *) inHtml;
- (NSString *) justAStringMethod;
#end
And method defined and called like this...
MyObject.m --- method declaration and usage. Trimmed down
#import "MyObject.h"
#implementation MyObject
- (NSString *) flattenHTML:(NSString *) inHtml {
NSScanner *theScanner;
NSString *text = nil;
theScanner = [NSScanner scannerWithString:inHtml];
while ([theScanner isAtEnd] == NO) {
[theScanner scanUpToString:#"<" intoString:NULL] ;
[theScanner scanUpToString:#">" intoString:&text] ;
inHtml = [inHtml stringByReplacingOccurrencesOfString:[NSString stringWithFormat:#"%#>", text] withString:#""];
}
//
inHtml = [inHtml stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
return inHtml;
}
- (NSString *) justAStringMethod
{
// Some calls.
}
- (void) useFlattenHTML
{
NSString* resultStr = [self.flattenHTML #"Some html tagged string"];
NSString* anotherStr = [self.justAStringMethod];
}
#end
I get
Property 'flattenHTML' not found on object of type 'MyObject *'
Maybe because you're using the dot notation in a case where it doesn't make much sense :
in useFlattenHTML method, self.flattenHTML is the same as [self flattenHTML], which doesn't exist, as you only have [self flattenHTML:someString].
On top of that, dot notation is possible, but you should keep it for fields declared as #property only

Simple addObject to NSMutableArray method gives lldb error

I'm adding objects to a NSMutableArray stack in my model. Here's the interface:
#interface calcModel ()
#property (nonatomic, strong) NSMutableArray *operandStack;
#end
And the implementation:
#implementation calcModel
#synthesize operandStack = _operandStack;
- (NSMutableArray *)operandStack;
{
if (_operandStack == nil) _operandStack = [[NSMutableArray alloc]init];
return _operandStack;
}
This addobject method works fine:
- (void)pushValue:(double)number;
{
[self.operandStack addObject:[NSNumber numberWithDouble:number]];
NSLog(#"Array: %#", self.operandStack);
}
but this one crashes the app and just says 'lldb' in the log:
- (void)pushOperator:(NSString *)operator;
{
[self.operandStack addObject:operator];
NSLog(#"Array: %#", self.operandStack);
}
What's causing this error?
The NSString you're adding is probably nil. Do this:
- (void)pushOperator:(NSString *)operator {
if (operator) {
[self.operandStack addObject:operator];
NSLog(#"Array: %#", self.operandStack);
} else {
NSLog(#"Oh no, it's nil.");
}
}
If that's the case, figure out why it's nil and fix that. Or check it before adding it.
The reason why the first method doesn't crash is, because there is no double value that can't be used to init an NSNumber, so it will never be nil.