2 // ContainerDetailViewController.m
5 // Created by Mike Mayo on 12/22/10.
6 // The OpenStack project is provided under the Apache 2.0 license.
9 #import "ContainerDetailViewController.h"
10 #import "OpenStackAccount.h"
12 #import "ActivityIndicatorView.h"
13 #import "AccountManager.h"
14 #import "UIViewController+Conveniences.h"
15 #import "UIColor+MoreColors.h"
16 #import "ReferrerACLViewController.h"
17 #import "UserAgentACLViewController.h"
18 #import "ContainersViewController.h"
23 #define kCDNAttributes 2
24 #define kLogRetention 3
25 #define kReferrerACL 4
26 #define kUserAgentACL 5
31 #define kCDNAttributes 2
32 #define kLogRetention 3
33 #define kReferrerACL 4
34 #define kUserAgentACL 5
38 Publish to CDN [On/Off]
39 @"Containers published to the CDN will be viewable to everyone. If you disable CDN access, container contents will not be purged from the CDN until the TTL expires."
44 Log Retention [On/Off]
45 @"When Log Retention is enabled, CDN access logs will be stored in the .CDN_ACCESS_LOGS container in your account."
48 @"The Referrer ACL is a Perl Compatible Regular Expression (PCRE) that must match the referrer in order for container contents to be served. This is a useful mechanism to prevent other content providers from hot-linking your CDN content."
51 @"The User Agent ACL is a PCRE that must match the user agent that your users are using to access the CDN content."
55 @implementation ContainerDetailViewController
57 @synthesize account, container, containersViewController, selectedContainerIndexPath;
59 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
60 return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
63 - (void)setBackgroundView {
64 if (!self.container) {
65 UIView *viewContainer = [[UIView alloc] init];
66 viewContainer.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
67 viewContainer.backgroundColor = [UIColor iPadTableBackgroundColor];
69 UILabel *label = [[UILabel alloc] init];
70 label.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
71 label.backgroundColor = [UIColor clearColor];
72 label.textColor = [UIColor emptyCollectionGrayColor];
73 label.font = [UIFont boldSystemFontOfSize:18.0];
74 label.text = @"No container selected";
75 label.textAlignment = UITextAlignmentCenter;
76 [viewContainer addSubview:label];
79 self.tableView.backgroundView = viewContainer;
80 [viewContainer release];
85 #pragma mark View lifecycle
89 cdnEnabledSwitch = [[UISwitch alloc] init];
90 cdnEnabledSwitch.on = container.cdnEnabled;
91 [cdnEnabledSwitch addTarget:self action:@selector(cdnEnabledSwitchChanged:) forControlEvents:UIControlEventValueChanged];
93 logRetentionSwitch = [[UISwitch alloc] init];
94 logRetentionSwitch.on = container.logRetention;
95 [logRetentionSwitch addTarget:self action:@selector(logRetentionSwitchChanged:) forControlEvents:UIControlEventValueChanged];
97 ttlSlider = [[UISlider alloc] init];
98 cdnURLActionSheet = [[UIActionSheet alloc] initWithTitle:container.cdnURL delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Copy to Pasteboard", nil];
99 deleteActionSheet = [[UIActionSheet alloc] initWithTitle:@"Are you sure you want to delete this container? This operation cannot be undone." delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Delete Container" otherButtonTitles:nil];
101 deleteSection = container.cdnEnabled ? 6 : 2;
104 - (void)viewWillAppear:(BOOL)animated {
105 [super viewWillAppear:animated];
107 self.navigationItem.title = container.name;
109 self.navigationItem.title = @"Cloud Files Container";
111 originalTTL = container.ttl;
112 [self setBackgroundView];
118 - (float)ttlToPercentage {
119 return self.container.ttl / 259200.0;
122 - (NSInteger)ttlFromPercentage:(float)percentage {
123 return percentage * 259200;
126 - (NSString *)ttlToHours {
127 NSString *result = [NSString stringWithFormat:@"%.0f hours", self.container.ttl / 3600.0];
128 if ([result isEqualToString:@"1 hours"]) {
134 - (void)ttlSliderFinished:(id)sender {
135 NSString *activityMessage = @"Updating TTL...";
136 activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
137 [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y];
139 [self.account.manager updateCDNContainer:self.container];
141 successObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerSucceeded" object:self.container
142 queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification)
144 [activityIndicatorView removeFromSuperviewAndRelease];
145 [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
148 failureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerFailed" object:self.container
149 queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification)
151 [activityIndicatorView removeFromSuperviewAndRelease];
152 container.ttl = originalTTL;
153 [self.tableView reloadData];
154 [self alert:@"There was a problem updating this container." request:[notification.userInfo objectForKey:@"request"]];
155 [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
159 - (void)ttlSliderMoved:(id)sender {
160 CGFloat newTTL = ttlSlider.value;
161 self.container.ttl = [self ttlFromPercentage:newTTL];
162 ttlLabel.text = [self ttlToHours];
167 #pragma mark Table view data source
169 - (CGFloat)findLabelHeight:(NSString*)text font:(UIFont *)font {
170 CGSize textLabelSize;
172 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
173 textLabelSize = CGSizeMake(577.0, 9000.0f);
175 textLabelSize = CGSizeMake(260.0, 9000.0f);
177 // pad \n\n to fix layout bug
178 CGSize stringSize = [text sizeWithFont:font constrainedToSize:textLabelSize lineBreakMode:UILineBreakModeWordWrap];
179 return stringSize.height;
182 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
183 if (indexPath.section == deleteSection) {
184 return tableView.rowHeight;
185 } else if (indexPath.section == kCDNAttributes) {
186 if (indexPath.row == 0) { // URL
187 return tableView.rowHeight;
188 //return 22.0 + [self findLabelHeight:container.cdnURL font:[UIFont systemFontOfSize:18.0]];
189 } else { // if (indexPath.row == 1) {
190 return tableView.rowHeight + ttlSlider.frame.size.height + 3.0;
193 return tableView.rowHeight;
197 - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
198 if (section == deleteSection) {
199 return @"Only empty containers can be deleted.";
200 } else if (section == kCDNAccess) {
201 //return @"CDN allows you to access files in this container via the public internet. Transfer charges apply.";
202 return @"CDN allows you to access files via the public internet. Transfer charges apply.";
203 } else if (section == kLogRetention) {
204 return @"When enabled, access logs will be stored in the .CDN_ACCESS_LOGS container.";
205 } else if (section == kReferrerACL) {
206 return @"The Referrer ACL is a Perl Compatible Regular Expression that must match the referrer for all content requests.";
207 } else if (section == kUserAgentACL) {
208 return @"The User Agent ACL is a Perl Compatible Regular Expression that must match the user agent for all content requests.";
214 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
215 if (self.container) {
217 return container.cdnEnabled ? 3 : 7;
219 return container.cdnEnabled ? 7 : 3;
226 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
227 // Return the number of rows in the section.
228 if (section == deleteSection) {
230 } else if (section == kOverview) {
232 } else if (section == kCDNAccess) {
234 } else if (section == kCDNAttributes) {
241 - (UITableViewCell *)tableView:(UITableView *)tableView ttlCellForRowAtIndexPath:(NSIndexPath *)indexPath {
242 static NSString *CellIdentifier = @"TTLCell";
244 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
246 cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
247 cell.selectionStyle = UITableViewCellSelectionStyleNone;
249 UILabel *textLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 13.0, 280.0, 20.0)];
250 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
251 textLabel.frame = CGRectMake(54.0, 13.0, 458.0, 20.0);
253 textLabel.font = [UIFont boldSystemFontOfSize:17.0];
254 textLabel.text = @"TTL";
255 textLabel.textColor = [UIColor blackColor];
256 textLabel.backgroundColor = [UIColor clearColor];
257 [cell addSubview:textLabel];
260 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
261 ttlSlider.frame = CGRectMake(54.0, 38.0, 596.0, ttlSlider.frame.size.height);
263 ttlSlider.frame = CGRectMake(20.0, 38.0, 280.0, ttlSlider.frame.size.height);
265 [ttlSlider addTarget:self action:@selector(ttlSliderMoved:) forControlEvents:UIControlEventValueChanged];
266 [ttlSlider addTarget:self action:@selector(ttlSliderFinished:) forControlEvents:UIControlEventTouchUpInside];
268 [cell addSubview:ttlSlider];
269 ttlLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 14.0, 280.0, 18.0)];
270 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
271 ttlLabel.frame = CGRectMake(54.0, 14.0, 596.0, 18.0);
273 ttlLabel.font = [UIFont systemFontOfSize:17.0];
274 ttlLabel.textColor = [UIColor value1DetailTextLabelColor];
275 ttlLabel.backgroundColor = [UIColor clearColor];
276 ttlLabel.textAlignment = UITextAlignmentRight;
277 [cell addSubview:ttlLabel];
280 ttlLabel.text = [self ttlToHours];
281 ttlSlider.value = [self ttlToPercentage];
286 - (UITableViewCell *)tableView:(UITableView *)tableView deleteCellForRowAtIndexPath:(NSIndexPath *)indexPath {
287 static NSString *CellIdentifier = @"DeleteCell";
289 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
291 cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
292 cell.textLabel.textAlignment = UITextAlignmentCenter;
293 cell.textLabel.text = @"Delete Container";
296 if (self.container.rootFolder) {
297 if (self.container.count == 0 || ([self.container.rootFolder.folders count] + [self.container.rootFolder.objects count] == 0)) {
298 cell.textLabel.textColor = [UIColor blackColor];
299 cell.selectionStyle = UITableViewCellSelectionStyleBlue;
301 cell.textLabel.textColor = [UIColor grayColor];
302 cell.selectionStyle = UITableViewCellSelectionStyleNone;
305 if (self.container.count == 0) {
306 cell.textLabel.textColor = [UIColor blackColor];
307 cell.selectionStyle = UITableViewCellSelectionStyleBlue;
309 cell.textLabel.textColor = [UIColor grayColor];
310 cell.selectionStyle = UITableViewCellSelectionStyleNone;
317 // Customize the appearance of table view cells.
318 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
320 static NSString *CellIdentifier = @"Cell";
322 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
324 cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
325 cell.selectionStyle = UITableViewCellSelectionStyleNone;
326 cell.textLabel.backgroundColor = [UIColor clearColor];
327 cell.detailTextLabel.backgroundColor = [UIColor clearColor];
328 cell.detailTextLabel.numberOfLines = 0;
329 cell.detailTextLabel.lineBreakMode = UILineBreakModeWordWrap;
330 cell.detailTextLabel.textAlignment = UITextAlignmentLeft;
333 cell.accessoryType = UITableViewCellAccessoryNone;
334 cell.selectionStyle = UITableViewCellSelectionStyleNone;
336 if (indexPath.section == kOverview) {
337 cell.accessoryView = nil;
338 if (indexPath.row == 0) {
339 cell.textLabel.text = @"Name";
340 cell.detailTextLabel.text = container.name;
341 } else if (indexPath.row == 1) {
342 cell.textLabel.text = @"Size";
343 cell.detailTextLabel.text = [container humanizedSize];
345 } else if (indexPath.section == kCDNAccess) {
346 cell.textLabel.text = @"Publish to CDN";
347 cell.detailTextLabel.text = @"";
348 cell.accessoryView = cdnEnabledSwitch;
349 cell.selectionStyle = UITableViewCellSelectionStyleNone;
350 } else if (indexPath.section == deleteSection) {
351 return [self tableView:tableView deleteCellForRowAtIndexPath:indexPath];
352 } else if (indexPath.section == kCDNAttributes) {
353 if (indexPath.row == 0) {
354 cell.textLabel.text = @"Public URL";
355 //cell.detailTextLabel.text = container.cdnURL;
356 cell.detailTextLabel.text = @"";
357 cell.accessoryView = nil;
358 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
359 cell.selectionStyle = UITableViewCellSelectionStyleBlue;
360 cell.detailTextLabel.lineBreakMode = UILineBreakModeTailTruncation;
361 cell.detailTextLabel.numberOfLines = 0;
362 //cell.detailTextLabel.adjustsFontSizeToFitWidth = YES;
363 } else if (indexPath.row == 1) {
364 return [self tableView:tableView ttlCellForRowAtIndexPath:indexPath];
366 } else if (indexPath.section == kLogRetention) {
367 cell.textLabel.text = @"Log Retention";
368 cell.detailTextLabel.text = @"";
369 cell.accessoryView = logRetentionSwitch;
370 cell.accessoryType = UITableViewCellAccessoryNone;
371 cell.selectionStyle = UITableViewCellSelectionStyleNone;
372 } else if (indexPath.section == kReferrerACL) {
373 cell.textLabel.text = @"Referrer ACL";
374 cell.detailTextLabel.text = container.referrerACL;
375 cell.accessoryView = nil;
376 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
377 cell.selectionStyle = UITableViewCellSelectionStyleBlue;
378 cell.detailTextLabel.numberOfLines = 1;
379 } else if (indexPath.section == kUserAgentACL) {
380 cell.textLabel.text = @"User Agent ACL";
381 cell.detailTextLabel.text = container.useragentACL;
382 cell.accessoryView = nil;
383 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
384 cell.selectionStyle = UITableViewCellSelectionStyleBlue;
385 cell.detailTextLabel.numberOfLines = 1;
392 #pragma mark Table view delegate
394 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
395 if (indexPath.section == deleteSection) {
396 if (self.container.count == 0 || ([self.container.rootFolder.folders count] + [self.container.rootFolder.objects count] == 0)) {
397 [deleteActionSheet showInView:self.view];
399 } else if (indexPath.section == kCDNAttributes && indexPath.row == 0) {
400 [cdnURLActionSheet showInView:self.view];
401 } else if (indexPath.section == kReferrerACL) {
402 ReferrerACLViewController *vc = [[ReferrerACLViewController alloc] initWithNibName:@"ReferrerACLViewController" bundle:nil];
403 vc.account = self.account;
404 vc.container = self.container;
405 vc.containerDetailViewController = self;
406 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
407 vc.modalPresentationStyle = UIModalPresentationFormSheet;
408 [self presentModalViewControllerWithNavigation:vc animated:YES];
410 [self.navigationController pushViewController:vc animated:YES];
413 } else if (indexPath.section == kUserAgentACL) {
414 UserAgentACLViewController *vc = [[UserAgentACLViewController alloc] initWithNibName:@"UserAgentACLViewController" bundle:nil];
415 vc.account = self.account;
416 vc.container = self.container;
417 vc.containerDetailViewController = self;
418 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
419 vc.modalPresentationStyle = UIModalPresentationFormSheet;
420 [self presentModalViewControllerWithNavigation:vc animated:YES];
422 [self.navigationController pushViewController:vc animated:YES];
429 #pragma mark Switches
431 - (void)cdnEnabledSwitchChanged:(id)sender {
433 NSString *activityMessage = @"Disabling CDN Access...";
434 if (!container.cdnEnabled) {
435 activityMessage = @"Enabling CDN Access...";
437 activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
438 [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y];
439 container.cdnEnabled = !container.cdnEnabled;
440 [self.account.manager updateCDNContainer:container];
442 successObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerSucceeded" object:self.container
443 queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification)
445 [activityIndicatorView removeFromSuperviewAndRelease];
447 NSIndexSet *sections = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(3, 4)];
448 NSInteger oldDeleteSection = deleteSection;
449 if (container.cdnEnabled) {
452 [self.tableView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(oldDeleteSection, 1)] withRowAnimation:UITableViewRowAnimationBottom];
454 [self.tableView insertSections:sections withRowAnimation:UITableViewRowAnimationBottom];
458 [self.tableView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(deleteSection, 1)] withRowAnimation:UITableViewRowAnimationTop];
460 [self.tableView deleteSections:sections withRowAnimation:UITableViewRowAnimationTop];
463 [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
466 failureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerFailed" object:self.container
467 queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification)
469 [activityIndicatorView removeFromSuperviewAndRelease];
470 container.cdnEnabled = !container.cdnEnabled;
471 cdnEnabledSwitch.on = !cdnEnabledSwitch.on;
472 [self alert:@"There was a problem updating this container." request:[notification.userInfo objectForKey:@"request"]];
473 [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
477 - (void)logRetentionSwitchChanged:(id)sender {
479 NSString *activityMessage = @"Disabling Log Retention...";
480 if (!container.logRetention) {
481 activityMessage = @"Enabling Log Retention...";
483 activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
484 [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y];
486 container.logRetention = !container.logRetention;
487 [self.account.manager updateCDNContainer:container];
489 successObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerSucceeded" object:self.container
490 queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification)
492 [activityIndicatorView removeFromSuperviewAndRelease];
493 [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
496 failureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerFailed" object:self.container
497 queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification)
499 [activityIndicatorView removeFromSuperviewAndRelease];
500 container.logRetention = !container.logRetention;
501 logRetentionSwitch.on = !logRetentionSwitch.on;
502 [self alert:@"There was a problem updating this container." request:[notification.userInfo objectForKey:@"request"]];
503 [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
508 #pragma mark Action Sheet
510 - (void)deleteContainerRow {
511 if ([self.account.containers count] == 0) {
512 [self.containersViewController.tableView reloadData];
514 [self.containersViewController.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:selectedContainerIndexPath] withRowAnimation:UITableViewRowAnimationLeft];
518 - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
519 if ([actionSheet isEqual:cdnURLActionSheet]) {
520 if (buttonIndex == 0) {
521 UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
522 [pasteboard setString:container.cdnURL];
524 [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:kCDNAttributes] animated:YES];
525 } else if ([actionSheet isEqual:deleteActionSheet]) {
526 if (buttonIndex == 0) {
528 NSString *activityMessage = @"Deleting container...";
529 activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
530 [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y];
532 [self.account.manager deleteContainer:self.container];
534 successObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"deleteContainerSucceeded" object:self.container
535 queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification)
537 [activityIndicatorView removeFromSuperviewAndRelease];
539 [self.account.containers removeObjectForKey:self.container.name];
540 [self.account persist];
543 if ([self.account.containers count] == 0 && UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
544 // on ipad, delete needs to get rid of the container on the main view
545 self.container = nil;
546 [self setBackgroundView];
547 [self.tableView reloadData];
549 [self.navigationController popViewControllerAnimated:YES];
552 [self.containersViewController.tableView selectRowAtIndexPath:selectedContainerIndexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
553 [NSTimer scheduledTimerWithTimeInterval:0.75 target:self selector:@selector(deleteContainerRow) userInfo:nil repeats:NO];
555 [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
558 failureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"deleteContainerFailed" object:self.container
559 queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification)
561 [activityIndicatorView removeFromSuperviewAndRelease];
562 [self alert:@"There was a problem deleting this container." request:[notification.userInfo objectForKey:@"request"]];
563 [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
568 [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:deleteSection] animated:YES];
574 #pragma mark Memory management
579 [cdnEnabledSwitch release];
581 [cdnURLActionSheet release];
582 [deleteActionSheet release];
583 [containersViewController release];
584 [selectedContainerIndexPath release];