What I want to do is have both UISegmentedControl boxes set the itemCondition and itemLocation object properties to their respective values, depending on which button is pressed.
This value will then be sent over to a Parse cloud code function as a parameter, as seen in the submitButton function. I know that with minPrice and maxPrice for example, those are user provided values, so you can send over self.minPrice.text as the param.
Setting the UISegmentedControl to self.itemCondition and sending that as a param doesn't seem to be working however. Since the segmented button is what sets the value, rather than the user explicitly typing something into a text box, I assume it is done differently, I'm just not sure how.
This is the code from my criteriaViewController that handles everything mentioned.
- (IBAction)conditionToggle:(id)sender{
if(Segment.selectedSegmentIndex == 0){
self.itemCondition == 'new';
}
else if(Segment.selectedSegmentIndex == 1){
self.itemCondition == 'any';
}
}
- (IBAction)itemLocationToggle:(id)sender {
if(Segment.selectedSegmentIndex == 0){
self.itemLocation == 'US';
}
else if(Segment.selectedSegmentIndex == 1){
self.itemLocation == 'WorldWide';
}
}
- (IBAction)submitButton:(id)sender
{
if (self.itemSearch.text.length > 0) {
//add all the info to users respective category object
//perform search with criteria just submitted
[PFCloud callFunctionInBackground:#"eBayCriteriaSearch"
withParameters:#{#"item": self.itemSearch.text,
#"minPrice": self.minPrice.text,
#"maxPrice": self.maxPrice.text,
#"itemCondition": self.itemCondition,
#"itemLocation": self.itemLocation,}
block:^(NSString *result, NSError *error) {
if (!error) {
NSLog(#"The result is '%#'", result);
if ([result intValue] == 1) {
[self performSegueWithIdentifier:#"ShowMatchCenterSegue" sender:self];
} else {
[self performSegueWithIdentifier:#"ShowCriteriaSegue" sender:self];
}
}
}];
}
}
You have a double equals in your assignment to self.itemCondition. That's a comparison operator. You need to use just '=' to assign a value.
Also, if itemCondition is an NSString, then you need to change the syntax for each assignment so it looks like this:
self.itemCondition = #"new";
Note the # and double quotes.
Also, I'd probably use a switch statement instead of several else if statements since you may have more segments in the future. So here's how the event method for your itemCondition segmented control would look for me.
- (IBAction)mySegmentedControl_ValueChanged:(id)sender {
switch (self.mySegmentedControl.selectedSegmentIndex) {
default:
case 0:
self.itemCondition = #"new";
break;
case 1:
self.itemCondition = #"any";
break;
}
}
Related
I have a block where I am checking a user's status property from firebase. If the status property is 'free' I want to return from the block, otherwise I want to search for another user and check their status and do so until a 'free' user has been found:
void( ^ myResponseBlock)(BOOL finished) = ^ void(BOOL finished) {
if (finished) {
if ([self.freedom isEqualToString: #"free"]) {
NSLog(#"free!");
return;
} else if ([self.freedom isEqualToString: #"matched"]) {
NSLog(#"get another user");
//get another user
do {
//picking another random user from array
rando = arc4random_uniform(arraycount);
}
while (rando == randomIndex && rando == [self.randString intValue]);
self.randString = [NSString stringWithFormat: #"%u", rando];
[users removeAllObjects];
[users addObject:usersArray[rando]];
self.freeUser = users.firstObject;
NSLog(#"set up another check");
//error is called after this block is called here, again
[self checkIfFree: myResponseBlock];
} else {
NSLog(#"error!");
}
} else {
NSLog(#"not finished the checking yet");
}
};
[self checkIfFree: myResponseBlock];
As shown, I'm getting an error of 'BAD ACCESS' when the block is called for a second time on the 'compblock(YES)' line below:
-(void)checkIfFree:(myCompletion) compblock{
self.freeUserFB = [[Firebase alloc] initWithUrl:[NSString stringWithFormat: #"https://skipchat.firebaseio.com/users/%#", self.freeUser.objectId]];
[self.freeUserFB observeEventType:FEventTypeValue withBlock:^(FDataSnapshot *snapshot)
{
self.otherStatus = snapshot.value[#"status"];
NSLog(#"snapshot info %#", snapshot.value);
if ([self.otherStatus isEqualToString:#"free"]) {
self.userIsFree = YES;
self.freedom = #"free";
NSLog(#"user is free in the check method %#", self.freedom);
}
else{
self.userIsFree = NO;
self.freedom = #"matched";
NSLog(#"user is matched in the check method %#", self.freedom);
}
compblock(YES);
}];
}
Everything is fine if the block does not have to be recalled and the first user that's checked is already 'free'. I'm stuck as to why I'm getting this error/crash and wondering how I can solve it!
Thanks!
A block captures all variables passed in including itself, however the variable myResponseBlock has not been initialized yet inside the block. Because of this, you are calling checkIfFree method with a nil value which in turn causing app to crash.
One thing you can do to overcome this would be declaring your block as a __block variable.
__block __weak void(^weakResponseBlock)(BOOL);
void(^myResponseBlock)(BOOL);
weakResponseBlock = myResponseBlock = ^void(BOOL finished) {
...
if (weakResponseBlock) {
[self checkIfFree:weakResponseBlock];
}
}
Additionally, please note that blocks retain all variables passed into them. In this case, you are retaining self inside the block, so it will never get deallocated as long as block executes. So unless required otherwise, always pass a weak reference to blocks.
__weak UIViewController *weakSelf = self;
weakResponseBlock = myResponseBlock = ^void(BOOL finished) {
...
if (weakResponseBlock) {
[weakSelf checkIfFree:weakResponseBlock];
}
}
I think still you might have an error because all your blocks are being created on the stack. So if anything async should happen the myResponseBlock will go away.
What I'd recommend is your copy (using the a property with copy attribute) your myResponse block into a property and reuse it from there. That way your block lives on the heap and goes away when self is set to nil.
I'm trying to use ReactiveCocoa to control binding and validation on a text field in my app. When I subscribe to a signal, it immediately does the binding from the text field to the model and runs the validation. Normally that wouldn't be an issue, but in this case the field is a 'password' input where the initial value from the model does not get copied to the text field. I want the binding and validation to trigger ONLY when the user actually types something in the field. Does anyone know of a way to do this?
Here is what I'm doing currently:
- (void)setUpBindings: forModel:(NSObject<ValidationModel> *)model {
NSString *property = #"password"
NSInteger throttleTime = 1.5;
[[[self.textField.rac_textSignal distinctUntilChanged]
throttle:throttleTime]
subscribeNext:^(id x) {
NSLog([NSString stringWithFormat:#"Model: %#, Value: %#", [model valueForKey:property], x]);
[model setValue:x forKey:property];
}];
[self bindValidator:[model.validators objectForKey:property]];
}
- (RACSignal *) passwordIsValid {
#weakify(self);
return [[RACObserve(self,password) distinctUntilChanged]
map:^id (NSString *newPassword) {
#strongify(self);
NSArray *errors = [self validatePassword];
return errors;
}];
}
-(void)bindValidator:(RACSignal *)validator
{
if(validator != nil)
{
[[[validator doNext:^(NSArray *errors) {
if(errors.count > 0)
{
NSError *error = [errors firstObject];
self.errorString =error.localizedDescription;
}
else
{
self.errorString = #"";
}
}]
map:^id(NSArray *errors) {
return errors.count <=0 ? #(1) : nil;
}] subscribeNext:^(id x) {
self.isValid = !!x;
}];
}
}
I have found a possible solution. ReactiveCocoa has a rac_signalForControlEvents method that lets you manually specify the event to observe. Using that, I was able to define an initial signal for the UIControlEventEditingChanged event of my text field. I then moved the setup for my binding and validation signals inside the subscribeNext, delaying their subscription until a change event is sent from the text field. My setup method from the OP would look like this:
- (void)setUpBindings:(NSString *)property forModel:(NSObject<ValidationModel> *)model {
NSInteger throttleTime = 1.5;
RACSignal *textChangeSignal = [[self.textField.rac_textSignal distinctUntilChanged]
throttle:throttleTime];
//wait to subscribe to the signal until the user actually makes changes to the field.
//the 'take:1' call ensures that the subscription only happens the first time the event
//is observed.
[[[self.textField rac_signalForControlEvents:UIControlEventEditingChanged]
take:1]
subscribeNext:^(id x) {
[self bindValidator:[model.validators objectForKey:self.reuseIdentifier]];
[textChangeSignal subscribeNext:^(id x) {
[model setValue:x forKey:property];
}];
}];
}
IMPORTANT: Notice the 'take:1' method in the outer chain. You MUST include this. Without that call, the outer 'subscribeNext' will run every time the editing event is fired, resulting in multiple subscribers for the same target and event. For more info see: How do I create a ReactiveCocoa subscriber that receives a signal only once, then unsubscribes/releases itself?
I'm going to leave this as open for now. This way works, but I am sure there must be a cleaner way of doing this.
You can use something like this :
#weakify(self);
RACSignal *validPasswordSignal = [self.passwordTextField.rac_textSignal map:^id(NSString *text) {
#strongify(self);
return #([self isValidPassword:text]);
}];
- (BOOL)isValidPassword:(NSString *)password
{
return ([password length] > 0);
}
You can change conditions in isValidPassword to anything you want to.
I want to hide a phone call completely in ios. My priority is to do this on ios 7 (latest ios version at this time!) but i would like to know how to hide a phone call on ios 6 and below too if possible. I have found some functions to do so as hooking into initWithAlertController method of class SBUIFullscreenAlertAdapter. Thanks to creker in this link I found another method to hook that is better to do so. The problem is it still has a callbar when the phone is not locked or when the phone is locked the phone shows that it's it in the middle of communication. Here are screenshots:
link to image
I want to know what are the methods dealing with this to hook? Is there anything else that i should know for achieving what i want?
For deleting any other traces that are left i thought of after the call is finished i delete the call history from it's database. Is there a better way?
I will try to post as much code as I can but it will not work from scratch. I use my own macroses to generate hooks so you have to rewrite them to work with your code. I will use pseudo function IsHiddenCall to determine if a given call is our hidden call (simple phone number check). It's here to simplify the code. You obviously have to implement it yourself. There will be other pseudo functions but their implementation is very simple and will be obvious from their names. It's not a simple tweak so bear with me.
Also, the code is non-ARC.
Basically, we hook everything that might tell iOS that there is a phone call.
iOS 7
Let's start with iOS 7 as it's the last version of iOS right now and hidden call implementation is simpler than on iOS 6 and below.
Almost everything we need is located in private TelephonyUtilities.framework. In iOS 7 Apple moved almost everything related to phone calls in that framework. That's why it got simpler - all other iOS components use that framework so we only need to hook it once without the need to poke around in every iOS daemon, framework that might do something with phone calls.
All methods are hooked in two processes - SpringBoard and MobilePhone (phone application). Bundle IDs are com.apple.springboard and com.apple.mobilephone, respectively.
Here is the list of TelephonyUtilities.framework methods I hook in both processes.
//TUTelephonyCall -(id)initWithCall:(CTCallRef)call
//Here we return nil in case of a hidden call. That way iOS will ignore it
//as it checks for nil return value.
InsertHookA(id, TUTelephonyCall, initWithCall, CTCallRef call)
{
if (IsHiddenCall(call) == YES)
{
return nil;
}
return CallOriginalA(TUTelephonyCall, initWithCall, call);
}
//TUCallCenter -(void)handleCallerIDChanged:(TUTelephonyCall*)call
//This is CoreTelephony notification handler. We ignore it in case of a hidden call.
//call==nil check is required because of our other hooks that might return
//nil object. Passing nil to original implementation might break something.
InsertHookA(void, TUCallCenter, handleCallerIDChanged, TUTelephonyCall* call)
{
if (call == nil || IsHiddenCall([call destinationID]) == YES)
{
return;
}
CallOriginalA(TUCallCenter, handleCallerIDChanged, call);
}
//TUCallCenter +(id)callForCTCall:(CTCallRef)call;
//Just like TUTelephonyCall -(id)initWithCall:(CTCallRef)call
InsertHookA(id, TUCallCenter, callForCTCall, CTCallRef call)
{
if (IsHiddenCall(call) == YES)
{
return nil;
}
return CallOriginalA(TUCallCenter, callForCTCall, call);
}
//TUCallCenter -(void)disconnectAllCalls
//Here we disconnect every call there is except our hidden call.
//This is required in case of a hidden conference call with hidden call.
//Our call will stay hidden but active while other call is active. This method is called
//when disconnect button is called - we don't wont it to cancel our hidden call
InsertHook(void, TUCallCenter, disconnectAllCalls)
{
DisconnectAllExceptHiddenCall();
}
//TUCallCenter -(void)disconnectCurrentCallAndActivateHeld
//Just like TUCallCenter -(void)disconnectAllCalls
InsertHook(void, TUCallCenter, disconnectCurrentCallAndActivateHeld)
{
DisconnectAllExceptHiddenCall();
}
//TUCallCenter -(int)currentCallCount
//Here we return current calls count minus our hidden call
InsertHook(int, TUCallCenter, currentCallCount)
{
return CallOriginal(TUCallCenter, currentCallCount) - GetHiddenCallsCount();
}
//TUCallCenter -(NSArray*)conferenceParticipantCalls
//Hide our call from conference participants
InsertHook(id, TUCallCenter, conferenceParticipantCalls)
{
NSArray* calls = CallOriginal(TUCallCenter, conferenceParticipantCalls);
BOOL isThereHiddenCall = NO;
NSMutableArray* callsWithoutHiddenCall = [NSMutableArray array];
for (id i in calls)
{
if (IsHiddenCall([i destinationID]) == NO)
{
[callsWithoutHiddenCall addObject:i];
}
else
{
isThereHiddenCall = YES;
}
}
if (callsWithoutHiddenCall.count != calls.count)
{
//If there is only two calls - hidden call and normal - there shouldn't be any sign of a conference call
if (callsWithoutHiddenCall.count == 1 && isThereHiddenCall == YES)
{
[callsWithoutHiddenCall removeAllObjects];
}
[self setConferenceParticipantCalls:callsWithoutHiddenCall];
[self _postConferenceParticipantsChanged];
}
else
{
return calls;
}
}
//TUTelephonyCall -(BOOL)isConferenced
//Hide conference call in case of two calls - our hidden and normal
InsertHook(BOOL, TUTelephonyCall, isConferenced)
{
if (CTGetCurrentCallCount() > 1)
{
if (CTGetCurrentCallCount() > 2)
{
//There is at least two normal calls - let iOS do it's work
return CallOriginal(TUTelephonyCall, isConferenced);
}
if (IsHiddenCallExists() == YES)
{
//There is hidden call and one normal call - conference call should be hidden
return NO;
}
}
return CallOriginal(TUTelephonyCall, isConferenced);
}
//TUCallCenter -(void)handleCallStatusChanged:(TUTelephonyCall*)call userInfo:(id)userInfo
//Call status changes handler. We ignore all events except those
//that we marked with special key in userInfo object. Here we answer hidden call, setup
//audio routing and doing other stuff. Our hidden call is indeed hidden,
//iOS doesn't know about it and don't even setup audio routes. "AVController" is a global variable.
InsertHookAA(void, TUCallCenter, handleCallStatusChanged, userInfo, TUTelephonyCall* call, id userInfo)
{
//'call' is nil when this is a hidden call event that we should ignore
if (call == nil)
{
return;
}
//Detecting special key that tells us that we should process this hidden call event
if ([[userInfo objectForKey:#"HiddenCall"] boolValue] == YES)
{
if (CTCallGetStatus(call) == kCTCallStatusIncoming)
{
CTCallAnswer(call);
}
else if (CTCallGetStatus(call) == kCTCallStatusActive)
{
//Setting up audio routing
[AVController release];
AVController = [[objc_getClass("AVController") alloc] init];
SetupAVController(AVController);
}
else if (CTCallGetStatus(call) == kCTCallStatusHanged)
{
NSArray *calls = CTCopyCurrentCalls(nil);
for (CTCallRef call in calls)
{
CTCallResume(call);
}
[calls release];
if (CTGetCurrentCallCount() == 0)
{
//No calls left - destroying audio controller
[AVController release];
AVController = nil;
}
}
return;
}
else if (IsHiddenCall([call destinationID]) == YES)
{
return;
}
CallOriginalAA(TUCallCenter, handleCallStatusChanged, userInfo, call, userInfo);
}
Here is Foundation.framework method I hook in both processes.
//In iOS 7 telephony events are sent through local NSNotificationCenter. Here we suppress all hidden call notifications.
InsertHookAAA(void, NSNotificationCenter, postNotificationName, object, userInfo, NSString* name, id object, NSDictionary* userInfo)
{
if ([name isEqualToString:#"TUCallCenterControlFailureNotification"] == YES || [name isEqualToString:#"TUCallCenterCauseCodeNotification"] == YES)
{
//'object' usually holds TUCall object. If 'object' is nil it indicates that these notifications are about hidden call and should be suppressed
if (object == nil)
{
return;
}
}
//Suppressing if something goes through
if ([object isKindOfClass:objc_getClass("TUTelephonyCall")] == YES && IsHiddenCall([object destinationID]) == YES)
{
return;
}
CallOriginalAAA(NSNotificationCenter, postNotificationName, object, userInfo, name, object, userInfo);
}
Here is the last method I hook in both processes from CoreTelephony.framwork
//CTCall +(id)callForCTCallRef:(CTCallRef)call
//Return nil in case of hidden call
InsertHookA(id, CTCall, callForCTCallRef, CTCallRef call)
{
if (IsHiddenCall(call) == YES)
{
return nil;
}
return CallOriginalA(CTCall, callForCTCallRef, call);
}
Here is SetupAVController function I used earlier. Hidden call is trully hidden - iOS doesn't know anything about it so when we answer it audio routing is not done and we will not hear anything on the other end. SetupAVController does this - it setups audio routing like iOS does when there is active phone call. I use private APIs from private Celestial.framework
extern id AVController_PickableRoutesAttribute;
extern id AVController_AudioCategoryAttribute;
extern id AVController_PickedRouteAttribute;
extern id AVController_AllowGaplessTransitionsAttribute;
extern id AVController_ClientPriorityAttribute;
extern id AVController_ClientNameAttribute;
extern id AVController_WantsVolumeChangesWhenPaused;
void SetupAVController(id controller)
{
[controller setAttribute:[NSNumber numberWithInt:10] forKey:AVController_ClientPriorityAttribute error:NULL];
[controller setAttribute:#"Phone" forKey:AVController_ClientNameAttribute error:NULL];
[controller setAttribute:[NSNumber numberWithBool:YES] forKey:AVController_WantsVolumeChangesWhenPaused error:NULL];
[controller setAttribute:[NSNumber numberWithBool:YES] forKey:AVController_AllowGaplessTransitionsAttribute error:NULL];
[controller setAttribute:#"PhoneCall" forKey:AVController_AudioCategoryAttribute error:NULL];
}
Here is method I hook only in MobilePhone process
/*
PHRecentCall -(id)initWithCTCall:(CTCallRef)call
Here we hide hidden call from call history. Doing it in MobilePhone
will hide our call even if we were in MobilePhone application when hidden call
was disconnected. We not only delete it from the database but also prevent UI from
showing it.
*/
InsertHookA(id, PHRecentCall, initWithCTCall, CTCallRef call)
{
if (call == NULL)
{
return CallOriginalA(PHRecentCall, initWithCTCall, call);
}
if (IsHiddenCall(call) == YES)
{
//Delete call from call history
CTCallDeleteFromCallHistory(call);
//Update MobilePhone app UI
id PHRecentsViewController = [[[[[UIApplication sharedApplication] delegate] rootViewController] tabBarViewController] recentsViewController];
if ([PHRecentsViewController isViewLoaded])
{
[PHRecentsViewController resetCachedIndexes];
[PHRecentsViewController _reloadTableViewAndNavigationBar];
}
}
return CallOriginalA(PHRecentCall, initWithCTCall, call);
}
Methods I hook in SpringBoard process.
//SpringBoard -(void)_updateRejectedInputSettingsForInCallState:(char)state isOutgoing:(char)outgoing triggeredbyRouteWillChangeToReceiverNotification:(char)triggered
//Here we disable proximity sensor
InsertHookAAA(void, SpringBoard, _updateRejectedInputSettingsForInCallState, isOutgoing, triggeredbyRouteWillChangeToReceiverNotification, char state, char outgoing, char triggered)
{
CallOriginalAAA(SpringBoard, _updateRejectedInputSettingsForInCallState, isOutgoing, triggeredbyRouteWillChangeToReceiverNotification, state, outgoing, triggered);
if (IsHiddenCallExists() == YES && CTGetCurrentCallCount() == 1)
{
BKSHIDServicesRequestProximityDetectionMode = (void (*)(int))dlsym(RTLD_SELF, "BKSHIDServicesRequestProximityDetectionMode");
BKSHIDServicesRequestProximityDetectionMode(0);
}
}
//BBServer -(void)publishBulletin:(id)bulletin destinations:(unsigned int)destinations alwaysToLockScreen:(char)toLockScreen
//Suppress hidden call bulletins
InsertHookAAA(void, BBServer, publishBulletin, destinations, alwaysToLockScreen, id bulletin, unsigned int destinations, char toLockScreen)
{
if ([[bulletin section] isEqualToString:#"com.apple.mobilephone"] == YES)
{
NSArray *recordTypeComponents = [[bulletin recordID] componentsSeparatedByString:#" "];
NSString *recordType = recordTypeComponents[0];
NSString *recordCode = recordTypeComponents[1];
//Missed call bulletin
if ([recordType isEqualToString:#"missedcall"] == YES)
{
NSArray *recordCodeComponents = [recordCode componentsSeparatedByString:#"-"];
NSString *phoneNumber = recordCodeComponents[0];
if (IsHiddenCall(phoneNumber) == YES)
{
return;
}
}
}
CallOriginalAAA(BBServer, publishBulletin, destinations, alwaysToLockScreen, bulletin, destinations, toLockScreen);
}
//TUCallCenter -(id)init
//CoreTelephony notifications handler setup
InsertHook(id, TUCallCenter, init)
{
CTTelephonyCenterAddObserver(CTTelephonyCenterGetDefault(), self, CallStatusNotificationCallback, kCTCallStatusChangeNotification, NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
return CallOriginal(TUCallCenter, init);
}
//Call status changes handler. Here we redirect status changes into hooked TUCallCenter method and doing some other stuff.
void CallStatusNotificationCallback(CFNotificationCenterRef center, void* observer, CFStringRef name, const void* object, CFDictionaryRef userInfo)
{
if (object == NULL)
{
return;
}
if (IsHiddenCall((CTCallRef)object) == YES)
{
[observer handleCallStatusChanged:object userInfo:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:#"HiddenCall"]];
}
else
{
if (CTCallGetStatus((CTCallRef)object) == kCTCallStatusHanged)
{
if (IsHiddenCallExists() == YES)
{
//Setting up all the audio routing again. When normal call is hanged iOS may break audio routing as it doesn't know there is another active call exists (hidden call)
SetupAVController(AVController);
}
else if (CTGetCurrentCallCount() == 0)
{
[AVController release];
AVController = nil;
}
}
}
if (CTGetCurrentCallCount() > 1 && IsHiddenCallExists() == YES)
{
//Here we setup hidden conference call
NSArray *calls = CTCopyCurrentCalls(nil);
for (CTCallRef call in calls)
{
CTCallJoinConference(call);
}
[calls release];
}
}
iOS 5-6
iOS 5-6 is more complex. Telephony code is scattered arount many iOS components and APIs. I might post the code later as I don't have time right now. The answer is already really long.
I have this slideshow app that has 3 images, I've set up some strings in my .h file and I'm trying to get the ratings of the 3 images stored in core data.
I've written the code to store it and I know it works, my problem is that for the first two images I have to have the code outside of the final image which also contains the code to stop & save the ratings to core data.
Because they are outside of the stopslideshow code, the values set to rating1 and rating2 aren't transferring to the second if statement. I'm hoping this will all make sense once you see the code below...
I found another question similar to this and it said you need to declare the strings outside of both if statements first, but that hasn't worked for me.
- (void) SlideShowEngineDidNext:(SlideShowEngine *)slideShow {
countImg += 1;
// If no rating selected on first or second image then set rating to "Null"
if ((_slideshow.currentIndex == 1) || (_slideshow.currentIndex == 2)) {
if (_Sam1.enabled == YES || _Sam2.enabled == YES || _Sam3.enabled == YES || _Sam4.enabled == YES || _Sam5.enabled == YES) {
rating = #"Null";
NSLog(#"SlideShowEngineDidNext, index: %d\nUser did not rate.\nRating: %#", slideShow.currentIndex, rating);
} else {
if (_slideshow.currentIndex == 1) {
_rating1 = rating;
}
if (_slideshow.currentIndex == 2) {
_rating2 = rating;
}
NSLog(#"SlideShowEngineDidNext, index: %d\nRating: %#", slideShow.currentIndex, rating);
}
}
if (countImg == slideShow.images.count) {
// If user didn't select a rating on last image then set the rating to "Null"
if (_slideshow.currentIndex == 0) {
if (_Sam1.enabled == YES || _Sam2.enabled == YES || _Sam3.enabled == YES || _Sam4.enabled == YES || _Sam5.enabled == YES) {
rating = #"Null";
NSLog(#"SlideShowEngineDidNext, index: %d\nUser did not rate.\nRating: %#", slideShow.currentIndex, rating);
} else {
_rating3 = rating;
NSLog(#"SlideShowEngineDidNext, index: %d\nRating: %#", slideShow.currentIndex, rating);
}
}
// Stop the slideshow
[_slideshow stop];
// Display alert to end slideshow
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Survey Completed!" message:#"Press OK to exit!" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
NSLog(#"rating1: %#", _rating1);
NSLog(#"rating2: %#", _rating2);
NSLog(#"rating3: %#", _rating3);
// Save ratings
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject* currentSurvey = [NSEntityDescription insertNewObjectForEntityForName:#"Ratings" inManagedObjectContext:context];
self.currentSurvey = currentSurvey;
[[self currentSurvey] setValue:_rating1 forKey:#"image1"];
[[self currentSurvey] setValue:_rating2 forKey:#"image2"];
[[self currentSurvey] setValue:_rating3 forKey:#"image3"];
NSError *error;
[[[self currentSurvey] managedObjectContext] save:&error];
}
}
From the NSLogs for rating1, 2 and 3 I'd get from this:
2014-01-11 17:06:35.145 Lab10 - Multimedia[41533:70b] rating1: (null)
2014-01-11 17:06:35.145 Lab10 - Multimedia[41533:70b] rating2: (null)
2014-01-11 17:06:35.146 Lab10 - Multimedia[41533:70b] rating3: 5
so from the if statement with currentIndex 1 and currentIndex2, the strings are being given their value but it's not transferring to the 2nd if statement where the slideshow ends and the data is saved.
if I try to save the data outside the ending if statement, then it just saves the first rating, then the first and second, and then all 3 ratings, all in different objects.
I just can't figure out the correct code placement, if there is any... to get this to work!
Thanks in advance.
Every time you run through this code you are creating a new NSManagedObject, essentially a new row in the database. Is that your intention?
Second, you are not capturing your errors on the save. This is bad. An error could be occurring and you would not know about it.
Have you walked through this code in the debugger and checked each value as you go through? Is the context !nil for example?
In trying to follow your conditional logic it appears that there are a lot of states you are not capturing and I suspect that is what is causing your nil values. You really need to walk through this, line by line, in the debugger and watch what the code is doing.
Your string assignments are just pointing to the same memory address all the time so whenever you change the value of rating any assignment also changes. Try using the following string assignments
_rating1 = [NSString stringWithString:rating];
_rating2 = [NSString stringWithString:rating];
_rating3 = [NSString stringWithString:rating];
See more here on Objective-C strings here http://www.techotopia.com/index.php/Working_with_String_Objects_in_Objective-C
THIS ANSWER WAS SUPPLIED BY THE OP:
Found the answer here
I had a problem with my NSStrings losing their value after being assigned, thanks for the guys who posted.
Found the answer here
I had a problem with my NSStrings losing their value after being assigned, thanks for the guys who posted.
I can get the folder_id by using [Box createFolderWithName:]. But when I try to use the folder_id to get its children, it does not work. Here's my code:
[Box createFolderWithName:#"My APP" parentFolderID:[Box rootFolderID] share:NO callbacks:^(id<BoxOperationCallbacks>on){
on.userInfo (^(NSDictionary* result) {
// do something with the return value (typically stored with key #"results") of the operation
NSNumber *appFolderId = [result objectForKey:#"folder_id"];
BoxFolder *appFolder = [Box folderWithID:appFolderId];
[appFolder updateWithCallbacks:^(id<BoxOperationCallbacks>on){
on.after(^(BoxCallbackResponse response) {
if (response == BoxCallbackResponseSuccessful) {
NSLog(#"Folder updated. Children count is: %d", [appFolder.children count]);
// Send a notification, call a delegate, use KVO use locally or whatever to use the children.
}
else {
NSLog(#"Folder not updated.");
}
});
}];
});
}];
children is always nil. I also tried with [Box rootFolder] but same result.
Can anyone help me with it? Thanks.
I think the following sample may help.
if (appFolder.isFolder) {
[appFolder updateWithCallbacks:^(id<BoxOperationCallbacks> on) {
on.after(^(BoxCallbackResponse response) {
if (response == BoxCallbackResponseSuccessful) {
NSLog(#"Folder updated. Children count is: %d", [appFolder.children count]);
// Send a notification, call a delegate, use KVO use locally or whatever to use the children.
}
else {
NSLog(#"Folder not updated.");
}
});
}];
}
else {
NSLog(#"NOT WORKING WITH A FOLDER!");
}