Converting my project to ARC but need help with these two bits of code to do with uploading and downloading files:
- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite{
[delegate performSelector:progressSelector withObject:(id)(100*totalBytesWritten /totalBytesExpectedToWrite)];
and then the following code, specifically the last line:
- (void)connection:(NSURLConnection *)con // IN
didReceiveData:(NSData *)data // IN
{
NSLog(#"%s: self:0x%p\n", __func__, self);
NSInteger dataLength;
const uint8_t * dataBytes;
NSInteger bytesWritten;
NSInteger bytesWrittenSoFar;
dataLength = data.length;
dataBytes = (const uint8_t * )data.bytes;
bytesWrittenSoFar = 0;
if(fileStream!=NULL)
{
do {
NSLog(#"%d",(int)bytesWrittenSoFar);
bytesWritten = [fileStream write:&dataBytes[bytesWrittenSoFar] maxLength:dataLength - bytesWrittenSoFar];
assert(bytesWritten != 0);
if (bytesWritten == -1)
{
[self downloadSucceeded:NO];
break;
}
else
{
bytesWrittenSoFar += bytesWritten;
}
}
while (bytesWrittenSoFar != dataLength);
}
dataSize+=data.length;
if(dataSize==downloadSize)
{
downloadDidSucceed=TRUE;
}
[delegate performSelector:progressSelector withObject:(id)(long)(100*dataSize/downloadSize)];
}
Any help is appreciated
Your problem is here
[delegate performSelector:progressSelector withObject:(id)(long)(100*dataSize/downloadSize)];
try this
[delegate performSelector:progressSelector withObject:[NSnumber numberWithLong:(100*dataSize/downloadSize)]];
In Objective-C there is distinction between scalar values like int/long/float/double and object types.
the id type is an anonymous object type. You don't know what it is, but you know that it is an object.
A long is not, and cannot be, an object. It is a simple scalar value. that's why the compiler isn't letting you cast your long to an ID type.
Sh_Khan's answer of wrapping your long value in an NSNumber solves the problem by creating an object that contains your value. You could also use an NSValue to get the same effect, but NSValue can represent things like structs that you can't represent with NSNumbers.
There are several system classes in Cocoa that are singletons, such as UIApplication, NSNotificationCenter. Now, I want to find all classes that are singleton, any suggestion that how could I quickly find them all?
I'm working on a huge codebase, and I need to separate the system singleton object from the customized singleton.
Objective-C runtime hackery! Fun!
Now, before I continue, I will present the disclaimer that I'd never recommend putting anything like this in actual shipping code, and that if you do, it's totally not my fault. This can be fun/interesting to do for educational purposes, though.
This isn't going to be an exact science, since the language itself doesn't have any actual concept of a "singleton". Basically, we're just looking for Objective-C classes that have class methods with certain giveaway prefixes. If we find one of those, there's a good chance that we have a singleton.
With that in mind:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
static BOOL ClassIsSingleton(Class class) {
unsigned int methodCount = 0;
Method *methods = class_copyMethodList(object_getClass(class), &methodCount);
#try {
for (unsigned int i = 0; i < methodCount; i++) {
Method eachMethod = methods[i];
// only consider class methods with no arguments
if (method_getNumberOfArguments(eachMethod) != 2) {
continue;
}
char *returnType = method_copyReturnType(eachMethod);
#try {
// only consider class methods that return objects
if (strcmp(returnType, #encode(id)) != 0) {
continue;
}
}
#finally {
free(returnType);
}
NSString *name = NSStringFromSelector(method_getName(methods[i]));
// look for class methods with telltale prefixes
if ([name hasPrefix:#"shared"]) {
return YES;
} else if ([name hasPrefix:#"standard"]) {
return YES;
} else if ([name hasPrefix:#"default"]) {
return YES;
} else if ([name hasPrefix:#"main"]) {
return YES;
} // feel free to add any additional prefixes here that I may have neglected
}
}
#finally {
free(methods);
}
return NO;
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSMutableArray *singletons = [NSMutableArray new];
int classCount = objc_getClassList(NULL, 0);
Class *classes = (Class *)malloc(classCount * sizeof(Class));
#try {
classCount = objc_getClassList(classes, classCount);
for (int i = 0; i < classCount; i++) {
Class eachClass = classes[i];
if (ClassIsSingleton(eachClass)) {
[singletons addObject:NSStringFromClass(eachClass)];
}
}
}
#finally {
free(classes);
}
NSLog(#"Singletons: %#", singletons);
}
return 0;
}
I have a class that holds attributes in a dictionary where the keys are well defined. I would like to replace this attribute dictionary with a class, let's call it AttributeSet. Where there were defined keys:
extern NSString *const Foo;
I would like to have properties:
#interface AttributeSet : NSObject
#property(strong) NSString *Foo;
...a ton more
#end
I would actually like the AttributeSet object to use a dictionary behind the scenes because for backwards compatibility reasons. So when this happens:
attributeSet.Foo = #"bar";
I actually want this to happen:
- (void)setFoo:(NSString *)foo {
self.attributes[Foo] = foo; //Foo is the extern variable Foo
}
but I don't want to have to define getters and setters for all of the properties.
I know that I can use key-value observing but that will 1) require me to have a mapping of (property name) #"Foo" --> (variable name) Foo and 2) result in both the property being set and the dictionary value being set when in reality I just want the dictionary to be set.
I know that I can do something like this: https://github.com/iosptl/ios6ptl/blob/master/ch28/Person/Person/Person.m
but that would 1) still require me to have a mapping and 2) require me to have an #dynamic for every property.
Is there a more automatic way to do this?
Thanks
To use the dynamically-generated accessor approach, as illustrated in the Person code you linked, without requiring #dynamic, you can declare the properties in a category on your class rather than the class itself:
#interface AttributeSet : NSObject
// ... no properties here ...
#end
#interface AttributeSet (YourPropertiesCategoryName)
#property(strong) NSString *Foo;
...a ton more
#end
The compiler will auto-synthesize properties declared in the class itself or in a class extension (which looks like a category with no category name), but not for a category.
Note that you don't need to and shouldn't provide an implementation for the category. (If you do, the compiler will complain about the lack of implementation for the properties. It won't auto-synthesize them, but you'll still need to use #dynamic to silence the warnings.)
After a bit of time, I think I've come up with quite the extensible solution for you. All it requires of you is to simply create your objects using the following helper class, like this:
#import "DictionaryBackedObject.h"
extern NSString *const foo;
NSString *const foo = #"Foo";
#interface Foo : NSObject
#property NSString *foo;
#end
#implementation Foo
#end
int main() {
Foo *object = [DictionaryBackedObject dictionaryBackedObjectOfType:[Foo class]
backingDictionary:#{ foo: #"Bar" }
mutable:NO];
NSLog(#"%#", [object foo]);
}
Note: This implementation is far from perfect, and it does use the 'dreaded' dlsym API, meaning, that you cannot strip your symbols from the executable should you wish to use this class. Also, it may cause rejection should this be submitted to the app store. There are other ways to automatically determine the key to use along with the dictionary, however, should you wish to find a workaround.
This implementation does support struct properties, as well as weak, copy, and atomic ones as well. It will be significantly slower than setting the property on a normal object, as this goes through objective-c's forwarding API (required to support struct returns).
Hopefully this helps you out, I certainly had a lot of fun making it.
DictionaryBackedObject.h
#interface DictionaryBackedObject : NSObject
+(id) dictionaryBackedObjectOfType:(Class) kls backingDictionary:(NSDictionary *) dictionary mutable:(BOOL) isMutable;
#end
DictionaryBackedObject.m
#import "DictionaryBackedObject.h"
#include <stdalign.h>
#include <dlfcn.h>
#import ObjectiveC.runtime;
#import ObjectiveC.message;
__attribute__((noinline))
static SEL property_getGetterSelector(objc_property_t property) {
char *getter = property_copyAttributeValue(property, "G");
if (getter) {
SEL result = sel_registerName(getter);
free(getter);
return result;
}
return sel_registerName(property_getName(property));
}
__attribute__((noinline))
static SEL property_getSetterSelector(objc_property_t property) {
char *setter = property_copyAttributeValue(property, "S");
if (setter) {
SEL result = sel_registerName(setter);
free(setter);
return result;
}
char buffer[512];
char propertyName[512];
strncpy(propertyName, property_getName(property), 512);
propertyName[0] = toupper(propertyName[0]);
snprintf(buffer, 512, "set%s", propertyName);
return sel_registerName(buffer);
}
struct objc_property_attributes_t {
union {
struct {
int nonatomic : 1;
int copy : 1;
int weak : 1;
int strong : 1;
};
int memory_mode;
};
int is_readonly;
int is_dynamic;
};
static inline BOOL property_isAttributeNull(objc_property_t property, const char *attr) {
void *value = property_copyAttributeValue(property, attr);
BOOL results = value == NULL;
free(value);
return results;
}
static struct objc_property_attributes_t property_getPropertyAttributes(objc_property_t property) {
struct objc_property_attributes_t attrs;
attrs.nonatomic = !property_isAttributeNull(property, "N");
attrs.copy = !property_isAttributeNull(property, "C");
attrs.strong = attrs.copy || !property_isAttributeNull(property, "&");
attrs.weak = !property_isAttributeNull(property, "W");
attrs.is_readonly = !property_isAttributeNull(property, "R");
attrs.is_dynamic = !property_isAttributeNull(property, "D");
return attrs;
}
static objc_property_t class_getPropertyForSelector(Class kls, SEL cmd) {
#define VALID_PROPERTY(property) \
(property != NULL && (property_getGetterSelector(property) == cmd || property_getSetterSelector(property) == cmd))
const char *selName = sel_getName(cmd);
objc_property_t results = class_getProperty(kls, selName);
if (VALID_PROPERTY(results))
return results;
if (strstr(selName, "set") == selName) {
char lowercaseSel[512];
strncpy(lowercaseSel, strstr(selName, "set"), 512);
lowercaseSel[0] = tolower(lowercaseSel[0]);
results = class_getProperty(kls, lowercaseSel);
if (VALID_PROPERTY(results)) return results;
}
// Easy paths exhausted, go the 'hard' way of looping over all of the properties available
results = NULL;
unsigned propertyCount = 0;
objc_property_t *properties = class_copyPropertyList(kls, &propertyCount);
for (unsigned propertyIndex = 0; propertyIndex < propertyCount; propertyIndex++) {
if (VALID_PROPERTY(properties[propertyIndex])) {
results = properties[propertyIndex];
break;
}
}
free(properties);
return results;
#undef VALID_PROPERTY
}
#implementation DictionaryBackedObject
-(id) initWithDictionary:(NSDictionary *) dictionary mutable:(BOOL) isMutable {
return nil;
}
+(Class) dictionaryBackedSubclassOfClass:(Class) kls {
#synchronized (kls) {
NSString *className = [NSStringFromClass(kls) stringByAppendingFormat:#"_dictionaryBacked"];
Class subclass = Nil;
if ((subclass = NSClassFromString(className))) {
return subclass;
}
subclass = objc_allocateClassPair(kls, [className UTF8String], 0);
class_addIvar(subclass, "_backingDictionary", sizeof(NSDictionary *), _Alignof(NSDictionary *), #encode(NSDictionary *));
class_addIvar(subclass, "_backingDictionaryIsMutable", sizeof(NSNumber *), _Alignof(NSNumber *), #encode(NSNumber *));
unsigned propertyCount = 0;
objc_property_t *properties = class_copyPropertyList(kls, &propertyCount);
for (unsigned i = 0; i < propertyCount; i++) {
objc_property_t property = properties[i];
char *type = property_copyAttributeValue(property, "T");
SEL getterSel = property_getGetterSelector(property);
SEL setterSel = property_getSetterSelector(property);
char getterTypeBuffer[512];
snprintf(getterTypeBuffer, 512, "%s#:", type);
char setterTypeBuffer[512];
snprintf(setterTypeBuffer, 512, "v#:%s", type);
NSUInteger typeSize;
NSUInteger typeAlignment;
NSGetSizeAndAlignment(type, &typeSize, &typeAlignment);
BOOL isStret = (typeSize * CHAR_BIT) > (WORD_BIT * 2);
class_addMethod(subclass, getterSel, isStret ? _objc_msgForward_stret : _objc_msgForward , getterTypeBuffer);
class_addMethod(subclass, setterSel, _objc_msgForward, setterTypeBuffer);
free(type);
}
free(properties);
Ivar backingDictionaryIvar = class_getInstanceVariable(subclass, "_backingDictionary");
Ivar backingDictionaryMutableIvar = class_getInstanceVariable(subclass, "_backingDictionaryIsMutable");
class_addMethod(subclass, #selector(forwardingTargetForSelector:), imp_implementationWithBlock(^id (id self) {
return nil;
}), "##:");
class_addMethod(subclass, #selector(forwardInvocation:), imp_implementationWithBlock(^void (id self, NSInvocation *invocation) {
SEL _cmd = [invocation selector];
objc_property_t property = class_getPropertyForSelector([self class], _cmd);
if (property == NULL) {
[self doesNotRecognizeSelector:_cmd];
return;
}
BOOL isGetter = (_cmd == property_getGetterSelector(property));
struct objc_property_attributes_t attributes = property_getPropertyAttributes(property);
NSString *propertyType = (__bridge_transfer NSString *) CFStringCreateWithCStringNoCopy(
NULL, property_copyAttributeValue(property, "T"), kCFStringEncodingUTF8, NULL
);
NSUInteger propertySize;
NSGetSizeAndAlignment([propertyType UTF8String], &propertySize, NULL);
void *dlsymKey = dlsym(RTLD_MAIN_ONLY, property_getName(property));
id dictionaryKey = *(__unsafe_unretained id *) dlsymKey;
NSMutableDictionary *backingDictionary = object_getIvar(self, backingDictionaryIvar);
NSNumber *isMutable = object_getIvar(self, backingDictionaryMutableIvar);
// Performing synchronization on nil is a no-op, see objc_sync.mm:306.
#synchronized (attributes.nonatomic ? nil : self) {
if (isGetter) {
id value = backingDictionary[dictionaryKey];
if (attributes.strong) {
[invocation setReturnValue:&value];
} else if (attributes.weak) {
value = [value nonretainedObjectValue];
[invocation setReturnValue:&value];
} else {
void *buffer = alloca(propertySize);
[value getValue:buffer];
[invocation setReturnValue:buffer];
}
} else {
if ((attributes.is_readonly || ![isMutable boolValue])) {
[self doesNotRecognizeSelector:_cmd];
return;
}
id dictionaryValue = nil;
void *newValue = alloca(propertySize);
[invocation getArgument:newValue atIndex:2];
if (attributes.strong) {
dictionaryValue = (__bridge id) newValue;
if (attributes.copy) {
dictionaryValue = [dictionaryValue copy];
}
} else if (attributes.weak) {
dictionaryValue = [NSValue valueWithNonretainedObject:(__bridge id) newValue];
} else {
dictionaryValue = [NSValue valueWithBytes:newValue objCType:[propertyType UTF8String]];
}
if (dictionaryValue == nil) {
[backingDictionary removeObjectForKey:dictionaryKey];
} else {
[backingDictionary setObject:dictionaryValue forKey:dictionaryKey];
}
}
}
}), "v#:#");
class_addMethod(subclass, #selector(initWithDictionary:mutable:), imp_implementationWithBlock(^id (id self, NSDictionary *dictionary, BOOL mutable) {
object_setIvar(self, backingDictionaryIvar, dictionary);
object_setIvar(self, backingDictionaryMutableIvar, #(mutable));
return self;
}), "##:#c");
objc_registerClassPair(subclass);
return subclass;
}
}
+(id) dictionaryBackedObjectOfType:(Class)kls backingDictionary:(NSDictionary *)dictionary mutable:(BOOL)isMutable {
Class subclass = [self dictionaryBackedSubclassOfClass:kls];
return [[subclass alloc] initWithDictionary:dictionary mutable:isMutable];
}
#end
Rob Napier's example is a good option; the compiler's going to generate accessors for you unless you tell it not to, and the way you tell it that is with the #dynamic directive.
Another option would be automated code generation: write a script to emit ObjC code for your setters.
The third that I can think of is overwriting the accessors during runtime. In your class's +initialize, you can get the list of its properties from the runtime library and use class_replaceMethod() to insert your own accessors that use your dictionary instead of the ivars. This will require some string mangling to get the accessor names and keys from each other.
Here's a gist with a demo of that last option: https://gist.github.com/woolsweater/4fb874b15449ee7fd7e8
I have one method which accepts va_list like this:
+(NSUInteger) addObjectToDB:(NSString*)dbFilePath withSQL:(NSString*)sql, ... {
va_list args;
va_start(args, sql);
FMDatabaseQueue* dbQ = [FMDatabaseQueue databaseQueueWithPath:dbFilePath];
__block NSUInteger result = -1;
[dbQ inDatabase:^(FMDatabase *db) {
[db open];
if ([db executeUpdate:sql, args]) {
result = (NSUInteger) [db lastInsertRowId];
}
[db close];
}];
va_end(args);
return result;
}
EDIT1:
I want to pass va_list(args) to the 'executeUpdate:' method of FMDatabase like this:
NSString* sql = [NSString stringWithFormat:#"Insert Into Table_Name Values (NULL, '%#', ?, ?)", #"string"];
[CXDBHelper addObjectToDB:self.dbFilePath withSQL:sql, NSData, NSData];
but the execution stopped in the method (FMDatabase.m) :
- (void)bindObject:(id)obj toColumn:(int)idx inStatement:(sqlite3_stmt*)pStmt {
if ((!obj) || ((NSNull *)obj == [NSNull null])) {
sqlite3_bind_null(pStmt, idx);
}
// FIXME - someday check the return codes on these binds.
else if ([obj isKindOfClass:[NSData class]]) {
at the last line without error message.
EDIT 2:
Thanks to #rmaddy's tips, I check the code executeUpdate:, it is defined as:
- (BOOL)executeUpdate:(NSString*)sql, ...
I realize that the problem is I cannot pass a va_list to it.
EDIT 3:
At last, I use another method which accept va_list: executeUpdate: withVAList: and everything is OK now.
I want to get filtred NSSet:
NSSet* contents = [self.content objectsPassingTest:^(id obj, BOOL* stop){
NSNumber* chapterNo = ((LTContent*)obj).chapterNo;
return [chapterNo integerValue] < 0;
}];
But this code fires an error: incompatible block pointer types sending 'int (^)(id, BOOL *)' to parameter of type 'BOOL (^)(id, BOOL *)
If I change code:
NSSet* contents = [self.content objectsPassingTest:^(id obj, BOOL* stop){
NSNumber* chapterNo = ((LTContent*)obj).chapterNo;
BOOL a = [chapterNo integerValue] < 0;
return a;
}];
it works perfect. But I don't want to use odd line. What's wrong in first snippet?
You forgot block's return type:
NSSet* contents = [self.content objectsPassingTest:^BOOL(id obj, BOOL* stop) {
Specify the explicit return type BOOL for the block:
NSSet* contents = [set objectsPassingTest:^BOOL(id obj, BOOL* stop) {
// ...
return [chapterNo integerValue] < 0;
}];
Otherwise the compiler derives the return type from the
return statement, and that is int in your case.