Index: src/OFHTTPClient.h ================================================================== --- src/OFHTTPClient.h +++ src/OFHTTPClient.h @@ -129,11 +129,11 @@ @interface OFHTTPClient: OFObject { #ifdef OF_HTTPCLIENT_M @public #endif - id _delegate; + OFObject *_delegate; bool _insecureRedirectsAllowed, _inProgress; OFTCPSocket *_socket; OFURL *_lastURL; bool _lastWasHEAD; OFHTTPResponse *_lastResponse; @@ -141,11 +141,11 @@ /*! * The delegate of the HTTP request. */ @property OF_NULLABLE_PROPERTY (assign, nonatomic) - id delegate; + OFObject *delegate; /*! * Whether redirects from HTTPS to HTTP will be allowed. */ @property (nonatomic) bool insecureRedirectsAllowed; Index: src/OFHTTPClient.m ================================================================== --- src/OFHTTPClient.m +++ src/OFHTTPClient.m @@ -255,17 +255,10 @@ selector: @selector(socketDidConnect:context: exception:) context: nil]; } -- (void)didCreateResponse: (OFHTTPResponse *)response -{ - [_client->_delegate client:_client - didPerformRequest:_request - response:response]; -} - - (void)createResponseWithSocket: (OFTCPSocket *)socket { OFURL *URL = [_request URL]; OFHTTPClientResponse *response; OFString *connectionHeader; @@ -396,13 +389,16 @@ exceptionWithRequest: _request response: response]; _client->_inProgress = false; - [self performSelector: @selector(didCreateResponse:) - withObject: response - afterDelay: 0]; + [_client->_delegate performSelector: @selector(client:didPerformRequest: + response:) + withObject: _client + withObject: _request + withObject: response + afterDelay: 0]; } - (bool)handleFirstLine: (OFString *)line { /* Index: src/OFObject.h ================================================================== --- src/OFObject.h +++ src/OFObject.h @@ -285,10 +285,27 @@ */ - (nullable id)performSelector: (SEL)selector withObject: (nullable id)object1 withObject: (nullable id)object2; +/*! + * @brief Performs the specified selector with the specified objects. + * + * @param selector The selector to perform + * @param object1 The first object that is passed to the method specified by the + * selector + * @param object2 The second object that is passed to the method specified by + * the selector + * @param object3 The third object that is passed to the method specified by the + * selector + * @return The object returned by the method specified by the selector + */ +- (nullable id)performSelector: (SEL)selector + withObject: (nullable id)object1 + withObject: (nullable id)object2 + withObject: (nullable id)object3; + /*! * @brief Checks two objects for equality. * * Classes containing data (like strings, arrays, lists etc.) should reimplement * this! @@ -733,10 +750,29 @@ - (void)performSelector: (SEL)selector withObject: (nullable id)object1 withObject: (nullable id)object2 afterDelay: (of_time_interval_t)delay; +/*! + * @brief Performs the specified selector with the specified objects after the + * specified delay. + * + * @param selector The selector to perform + * @param object1 The first object that is passed to the method specified by the + * selector + * @param object2 The second object that is passed to the method specified by + * the selector + * @param object3 The third object that is passed to the method specified by the + * selector + * @param delay The delay after which the selector will be performed + */ +- (void)performSelector: (SEL)selector + withObject: (nullable id)object1 + withObject: (nullable id)object2 + withObject: (nullable id)object3 + afterDelay: (of_time_interval_t)delay; + #ifdef OF_HAVE_THREADS /*! * @brief Performs the specified selector on the specified thread. * * @param selector The selector to perform @@ -778,10 +814,31 @@ onThread: (OFThread *)thread withObject: (nullable id)object1 withObject: (nullable id)object2 waitUntilDone: (bool)waitUntilDone; +/*! + * @brief Performs the specified selector on the specified thread with the + * specified objects. + * + * @param selector The selector to perform + * @param thread The thread on which to perform the selector + * @param object1 The first object that is passed to the method specified by the + * selector + * @param object2 The second object that is passed to the method specified by + * the selector + * @param object3 The third object that is passed to the method specified by the + * selector + * @param waitUntilDone Whether to wait until the perform finished + */ +- (void)performSelector: (SEL)selector + onThread: (OFThread *)thread + withObject: (nullable id)object1 + withObject: (nullable id)object2 + withObject: (nullable id)object3 + waitUntilDone: (bool)waitUntilDone; + /*! * @brief Performs the specified selector on the main thread. * * @param selector The selector to perform * @param waitUntilDone Whether to wait until the perform finished @@ -816,10 +873,29 @@ - (void)performSelectorOnMainThread: (SEL)selector withObject: (nullable id)object1 withObject: (nullable id)object2 waitUntilDone: (bool)waitUntilDone; +/*! + * @brief Performs the specified selector on the main thread with the specified + * objects. + * + * @param selector The selector to perform + * @param object1 The first object that is passed to the method specified by the + * selector + * @param object2 The second object that is passed to the method specified by + * the selector + * @param object3 The third object that is passed to the method specified by the + * selector + * @param waitUntilDone Whether to wait until the perform finished + */ +- (void)performSelectorOnMainThread: (SEL)selector + withObject: (nullable id)object1 + withObject: (nullable id)object2 + withObject: (nullable id)object3 + waitUntilDone: (bool)waitUntilDone; + /*! * @brief Performs the specified selector on the specified thread after the * specified delay. * * @param selector The selector to perform @@ -860,10 +936,31 @@ - (void)performSelector: (SEL)selector onThread: (OFThread *)thread withObject: (nullable id)object1 withObject: (nullable id)object2 afterDelay: (of_time_interval_t)delay; + +/*! + * @brief Performs the specified selector on the specified thread with the + * specified objects after the specified delay. + * + * @param selector The selector to perform + * @param thread The thread on which to perform the selector + * @param object1 The first object that is passed to the method specified by the + * selector + * @param object2 The second object that is passed to the method specified by + * the selector + * @param object3 The third object that is passed to the method specified by the + * selector + * @param delay The delay after which the selector will be performed + */ +- (void)performSelector: (SEL)selector + onThread: (OFThread *)thread + withObject: (nullable id)object1 + withObject: (nullable id)object2 + withObject: (nullable id)object3 + afterDelay: (of_time_interval_t)delay; #endif /*! * @brief This method is called when @ref resolveClassMethod: or * @ref resolveInstanceMethod: returned false. It should return a target Index: src/OFObject.m ================================================================== --- src/OFObject.m +++ src/OFObject.m @@ -555,10 +555,26 @@ id (*imp)(id, SEL, id, id) = (id (*)(id, SEL, id, id))objc_msgSend; #endif return imp(self, selector, object1, object2); } + +- (id)performSelector: (SEL)selector + withObject: (id)object1 + withObject: (id)object2 + withObject: (id)object3 +{ +#if defined(OF_OBJFW_RUNTIME) + id (*imp)(id, SEL, id, id, id) = + (id (*)(id, SEL, id, id, id))objc_msg_lookup(self, selector); +#elif defined(OF_APPLE_RUNTIME) + id (*imp)(id, SEL, id, id, id) = + (id (*)(id, SEL, id, id, id))objc_msgSend; +#endif + + return imp(self, selector, object1, object2, object3); +} - (void)performSelector: (SEL)selector afterDelay: (of_time_interval_t)delay { void *pool = objc_autoreleasePoolPush(); @@ -597,10 +613,29 @@ target: self selector: selector object: object1 object: object2 repeats: false]; + + objc_autoreleasePoolPop(pool); +} + +- (void)performSelector: (SEL)selector + withObject: (id)object1 + withObject: (id)object2 + withObject: (id)object3 + afterDelay: (of_time_interval_t)delay +{ + void *pool = objc_autoreleasePoolPush(); + + [OFTimer scheduledTimerWithTimeInterval: delay + target: self + selector: selector + object: object1 + object: object2 + object: object3 + repeats: false]; objc_autoreleasePoolPop(pool); } #ifdef OF_HAVE_THREADS @@ -658,10 +693,33 @@ if (waitUntilDone) [timer waitUntilDone]; objc_autoreleasePoolPop(pool); } + +- (void)performSelector: (SEL)selector + onThread: (OFThread *)thread + withObject: (id)object1 + withObject: (id)object2 + withObject: (id)object3 + waitUntilDone: (bool)waitUntilDone +{ + void *pool = objc_autoreleasePoolPush(); + OFTimer *timer = [OFTimer timerWithTimeInterval: 0 + target: self + selector: selector + object: object1 + object: object2 + object: object3 + repeats: false]; + [[thread runLoop] addTimer: timer]; + + if (waitUntilDone) + [timer waitUntilDone]; + + objc_autoreleasePoolPop(pool); +} - (void)performSelectorOnMainThread: (SEL)selector waitUntilDone: (bool)waitUntilDone { void *pool = objc_autoreleasePoolPush(); @@ -712,10 +770,32 @@ if (waitUntilDone) [timer waitUntilDone]; objc_autoreleasePoolPop(pool); } + +- (void)performSelectorOnMainThread: (SEL)selector + withObject: (id)object1 + withObject: (id)object2 + withObject: (id)object3 + waitUntilDone: (bool)waitUntilDone +{ + void *pool = objc_autoreleasePoolPush(); + OFTimer *timer = [OFTimer timerWithTimeInterval: 0 + target: self + selector: selector + object: object1 + object: object2 + object: object3 + repeats: false]; + [[OFRunLoop mainRunLoop] addTimer: timer]; + + if (waitUntilDone) + [timer waitUntilDone]; + + objc_autoreleasePoolPop(pool); +} - (void)performSelector: (SEL)selector onThread: (OFThread *)thread afterDelay: (of_time_interval_t)delay { @@ -757,10 +837,30 @@ target: self selector: selector object: object1 object: object2 repeats: false]]; + + objc_autoreleasePoolPop(pool); +} + +- (void)performSelector: (SEL)selector + onThread: (OFThread *)thread + withObject: (id)object1 + withObject: (id)object2 + withObject: (id)object3 + afterDelay: (of_time_interval_t)delay +{ + void *pool = objc_autoreleasePoolPush(); + + [[thread runLoop] addTimer: [OFTimer timerWithTimeInterval: delay + target: self + selector: selector + object: object1 + object: object2 + object: object3 + repeats: false]]; objc_autoreleasePoolPop(pool); } #endif Index: src/OFTimer.h ================================================================== --- src/OFTimer.h +++ src/OFTimer.h @@ -43,11 +43,11 @@ */ @interface OFTimer: OFObject { OFDate *_fireDate; of_time_interval_t _interval; - id _target, _object1, _object2; + id _target, _object1, _object2, _object3; SEL _selector; uint8_t _arguments; bool _repeats; #ifdef OF_HAVE_BLOCKS of_timer_block_t _block; @@ -124,10 +124,33 @@ selector: (SEL)selector object: (nullable id)object1 object: (nullable id)object2 repeats: (bool)repeats; +/*! + * @brief Creates and schedules a new timer with the specified time interval. + * + * @param timeInterval The time interval after which the timer should be fired + * @param target The target on which to call the selector + * @param selector The selector to call on the target + * @param object1 The first object to pass when calling the selector on the + * target + * @param object2 The second object to pass when calling the selector on the + * target + * @param object3 The third object to pass when calling the selector on the + * target + * @param repeats Whether the timer repeats after it has been executed + * @return A new, autoreleased timer + */ ++ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval + target: (id)target + selector: (SEL)selector + object: (nullable id)object1 + object: (nullable id)object2 + object: (nullable id)object3 + repeats: (bool)repeats; + #ifdef OF_HAVE_BLOCKS /*! * @brief Creates and schedules a new timer with the specified time interval. * * @param timeInterval The time interval after which the timer should be fired @@ -188,10 +211,33 @@ selector: (SEL)selector object: (nullable id)object1 object: (nullable id)object2 repeats: (bool)repeats; +/*! + * @brief Creates a new timer with the specified time interval. + * + * @param timeInterval The time interval after which the timer should be fired + * @param target The target on which to call the selector + * @param selector The selector to call on the target + * @param object1 The first object to pass when calling the selector on the + * target + * @param object2 The second object to pass when calling the selector on the + * target + * @param object3 The third object to pass when calling the selector on the + * target + * @param repeats Whether the timer repeats after it has been executed + * @return A new, autoreleased timer + */ ++ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval + target: (id)target + selector: (SEL)selector + object: (nullable id)object1 + object: (nullable id)object2 + object: (nullable id)object3 + repeats: (bool)repeats; + #ifdef OF_HAVE_BLOCKS /*! * @brief Creates a new timer with the specified time interval. * * @param timeInterval The time interval after which the timer should be fired @@ -266,10 +312,37 @@ selector: (SEL)selector object: (nullable id)object1 object: (nullable id)object2 repeats: (bool)repeats; +/*! + * @brief Initializes an already allocated timer with the specified time + * interval. + * + * @param fireDate The date at which the timer should fire + * @param interval The time interval after which to repeat the timer, if it is + * a repeating timer + * @param target The target on which to call the selector + * @param selector The selector to call on the target + * @param object1 The first object to pass when calling the selector on the + * target + * @param object2 The second object to pass when calling the selector on the + * target + * @param object3 The third object to pass when calling the selector on the + * target + * @param repeats Whether the timer repeats after it has been executed + * @return An initialized timer + */ +- initWithFireDate: (OFDate *)fireDate + interval: (of_time_interval_t)interval + target: (id)target + selector: (SEL)selector + object: (nullable id)object1 + object: (nullable id)object2 + object: (nullable id)object3 + repeats: (bool)repeats; + #ifdef OF_HAVE_BLOCKS /*! * @brief Initializes an already allocated timer with the specified time * interval. * Index: src/OFTimer.m ================================================================== --- src/OFTimer.m +++ src/OFTimer.m @@ -101,10 +101,37 @@ [timer retain]; objc_autoreleasePoolPop(pool); return [timer autorelease]; } + ++ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval + target: (id)target + selector: (SEL)selector + object: (id)object1 + object: (id)object2 + object: (id)object3 + repeats: (bool)repeats +{ + void *pool = objc_autoreleasePoolPush(); + OFDate *fireDate = [OFDate dateWithTimeIntervalSinceNow: timeInterval]; + id timer = [[[self alloc] initWithFireDate: fireDate + interval: timeInterval + target: target + selector: selector + object: object1 + object: object2 + object: object3 + repeats: repeats] autorelease]; + + [[OFRunLoop currentRunLoop] addTimer: timer]; + + [timer retain]; + objc_autoreleasePoolPop(pool); + + return [timer autorelease]; +} #ifdef OF_HAVE_BLOCKS + (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval repeats: (bool)repeats block: (of_timer_block_t)block @@ -185,10 +212,35 @@ [timer retain]; objc_autoreleasePoolPop(pool); return [timer autorelease]; } + ++ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval + target: (id)target + selector: (SEL)selector + object: (id)object1 + object: (id)object2 + object: (id)object3 + repeats: (bool)repeats +{ + void *pool = objc_autoreleasePoolPush(); + OFDate *fireDate = [OFDate dateWithTimeIntervalSinceNow: timeInterval]; + id timer = [[[self alloc] initWithFireDate: fireDate + interval: timeInterval + target: target + selector: selector + object: object1 + object: object2 + object: object3 + repeats: repeats] autorelease]; + + [timer retain]; + objc_autoreleasePoolPop(pool); + + return [timer autorelease]; +} #ifdef OF_HAVE_BLOCKS + (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval repeats: (bool)repeats block: (of_timer_block_t)block @@ -216,10 +268,11 @@ interval: (of_time_interval_t)interval target: (id)target selector: (SEL)selector object: (id)object1 object: (id)object2 + object: (id)object3 arguments: (uint8_t)arguments repeats: (bool)repeats OF_METHOD_FAMILY(init) { self = [super init]; @@ -228,10 +281,11 @@ _interval = interval; _target = [target retain]; _selector = selector; _object1 = [object1 retain]; _object2 = [object2 retain]; + _object3 = [object3 retain]; _arguments = arguments; _repeats = repeats; _valid = true; #ifdef OF_HAVE_THREADS _condition = [[OFCondition alloc] init]; @@ -253,10 +307,11 @@ return [self of_initWithFireDate: fireDate interval: interval target: target selector: selector object: nil + object: nil object: nil arguments: 0 repeats: repeats]; } @@ -270,10 +325,11 @@ return [self of_initWithFireDate: fireDate interval: interval target: target selector: selector object: object + object: nil object: nil arguments: 1 repeats: repeats]; } @@ -289,13 +345,34 @@ interval: interval target: target selector: selector object: object1 object: object2 + object: nil arguments: 2 repeats: repeats]; } + +- initWithFireDate: (OFDate *)fireDate + interval: (of_time_interval_t)interval + target: (id)target + selector: (SEL)selector + object: (id)object1 + object: (id)object2 + object: (id)object3 + repeats: (bool)repeats +{ + return [self of_initWithFireDate: fireDate + interval: interval + target: target + selector: selector + object: object1 + object: object2 + object: object3 + arguments: 3 + repeats: repeats]; +} #ifdef OF_HAVE_BLOCKS - initWithFireDate: (OFDate *)fireDate interval: (of_time_interval_t)interval repeats: (bool)repeats @@ -331,10 +408,11 @@ [_fireDate release]; [_target release]; [_object1 release]; [_object2 release]; + [_object3 release]; #ifdef OF_HAVE_BLOCKS [_block release]; #endif #ifdef OF_HAVE_THREADS [_condition release]; @@ -359,12 +437,13 @@ { void *pool = objc_autoreleasePoolPush(); id target = [[_target retain] autorelease]; id object1 = [[_object1 retain] autorelease]; id object2 = [[_object2 retain] autorelease]; + id object3 = [[_object3 retain] autorelease]; - OF_ENSURE(_arguments <= 2); + OF_ENSURE(_arguments <= 3); if (_repeats && _valid) { int missedIntervals = -[_fireDate timeIntervalSinceNow] / _interval; of_time_interval_t newFireDate; @@ -400,10 +479,16 @@ case 2: [target performSelector: _selector withObject: object1 withObject: object2]; break; + case 3: + [target performSelector: _selector + withObject: object1 + withObject: object2 + withObject: object3]; + break; } #ifdef OF_HAVE_BLOCKS } #endif @@ -450,13 +535,16 @@ _valid = false; [_target release]; [_object1 release]; [_object2 release]; + [_object3 release]; + _target = nil; _object1 = nil; _object2 = nil; + _object3 = nil; } #ifdef OF_HAVE_THREADS - (void)waitUntilDone {