lundi 29 juin 2015

Detect when second tableview cell comes into view - then perform an action


I've got a UITableView in a UIViewController, as well as a filter button. I hide the filter button when the user starts to scroll down the list. I want to then show the filter button when the second cell (index 1) is visible. However, I can't get this desired effect, I can only get it to appear when it reaches the top. Here is my code for when it reaches the top (I then show the filter button again).

//determines when the tableview was scrolled
-(void) scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGPoint currentOffset = scrollView.contentOffset;
     //tableview is scrolled down
    if (currentOffset.y > self.lastContentOffset.y)
      {

    //if the showFilter button is visible i.e alpha is greater than 0
        if (self.showFilter.alpha==1.0) {

            [UIView animateWithDuration:1 animations:^{

                //hide show filter button
                self.showFilter.alpha=0.0;
                //I also adjust the frames of a tableview here
            }];

        }


    }


    //determines if it is scrolled back to the top
    if (self.showFilter.alpha==0.0 && currentOffset.y==0) {
        [UIView animateWithDuration:0.3 animations:^{
            //show filter button
            self.showFilter.alpha=1.0;

          //i also adjust the frames of the tableview here
        }];
    }

    self.lastContentOffset = currentOffset;
}

I have also tried:

if (self.showFilter.alpha==0.0 && currentOffset.y<160)

But it doesn't work to the desired effect as the tableview jumps off the screen. Is there another way to get this desired effect?


Fetching JSON data after failed retrieval


In my application, I am fetching JSON data. Occasionally, the application will fail to fetch it and when I print the responseObject, it returns ( ). I would like to make an if statement so that when this happens, a UIAlertView will show up. Right now, I have an if statement saying that if self.jobs == nil, the alert will come up, but that is not working. I'd really appreciate any help!

- (void)viewDidLoad
{

[super viewDidLoad];

//Fetch JSON
NSString *urlAsString = [NSString stringWithFormat:@"http://ift.tt/1MXKCe4", LANGUAGE, TOWN];
NSURL *url = [NSURL URLWithString:urlAsString];
NSURLRequest *request = [NSURLRequest requestWithURL: url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];

//Parse JSON
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
self.jobs  = (NSArray *)responseObject;

if(self.jobs != nil)
{
    [self.tableView reloadData];
}
else
{
    UIAlertView* alert_view = [[UIAlertView alloc]
                               initWithTitle: @"Failed to retrieve data" message: nil delegate: self
                               cancelButtonTitle: @"cancel" otherButtonTitles: @"Retry", nil];
    [alert_view show];
}
}

//Upon failure
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
 UIAlertView *aV = [[UIAlertView alloc]
                           initWithTitle:@"Error" message:[error localizedDescription] delegate: nil
                                           cancelButtonTitle:@"Ok" otherButtonTitles:nil];
 [aV show];
 }];


Unexpectedly found nil while unwrapping an Optional value while opening UIViewController


I'm doing a simple tableview app with swift, in which you open a new view controller programatically after clicking on a table row:

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

//GLobals
@IBOutlet weak var table: UITableView!
//Table View Data

let cats :[String] = ["Gala","Vito","Odin","Ema"]

override func viewDidLoad() {
    super.viewDidLoad()

    table.delegate = self
    table.dataSource = self
}

// MARK:  UITextFieldDelegate Methods
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return cats.count
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = table.dequeueReusableCellWithIdentifier("CustomTextCell", forIndexPath: indexPath) as! UITableViewCell

    let row = indexPath.row
    cell.textLabel?.text = cats[row]

    return cell
}

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRowAtIndexPath(indexPath, animated: true)

    let row = indexPath.row
    let cat : String = cats[row];
    println(cat)

    //Save cat for detail view
    var defaults = NSUserDefaults.standardUserDefaults()
    defaults.setObject(cat, forKey: "cat")
    defaults.synchronize()


    let detail:Detail = Detail();
    self.presentViewController(detail, animated: true, completion: nil);
}
}

The code in the detail view is the following:

class Detail: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()
    self.view.backgroundColor = UIColor.whiteColor()

    let defeaults = NSUserDefaults.standardUserDefaults()

    let cat = defeaults.stringForKey("cat")

    var label = UILabel(frame: CGRectMake(0, 0, 200, 21))
    label.center = CGPointMake(160, 284)
    label.textAlignment = NSTextAlignment.Center
    label.text = cat

    self.view.addSubview(label)
}

override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
    let home:ViewController = ViewController()
    self.presentViewController(home, animated: true, completion: nil)
}

However when the app goes back to ViewController I'm having "unexpectedly found nil while unwrapping an Optional value "

the error

I have try some of the other answers to this problem including, warping with if == nil some of the values, but I still can't find what is the problem.

I'm assuming the UIViewController is not loading the UITableViewDelegate and UITableViewDataSource again, but I don't understand why... and how would you load them from another view anyway?


Trouble understanding resuming cells in collection views


I'm following a site to help learn swift and I'm getting confused about this part right here. Basically we added the if cell.imageview.image == nil statement so hat when the collection view loads and you scroll the image doesn't reload the filters. What I don't understand is if you scroll down a cell is reused for the bottom row, now why if I scroll back up doesn't it have to reload the filter? is that data saved somewhere so when I scroll up the properties don't have to repopulate? and If thats the case why would I have to use that if statement at all?

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

    let cell = collectionView.dequeueReusableCellWithReuseIdentifier("MyCell", forIndexPath: indexPath) as! FilterCell

    if cell.imageView.image == nil {
    cell.imageView.image = placeholder

    let filterQueue: dispatch_queue_t = dispatch_queue_create("filter queue", nil)

    dispatch_async(filterQueue, { () -> Void in
        let filterImage = self.filteredImageFromImage(self.thisFeeditem.thumbNail, filter: self.filters[indexPath.row])

        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            cell.imageView.image = filterImage
            })
        })
    }
    return cell
}


Make NSOperationQueue synchronous


How can I make NSOperationQueue synchronous? I did tried this by subclassing NSOperation and setting "setMaxConcurrentOperationCount" to 1. And also adding dependencies on previous operations using "addDependency" method.

Adding Code:

if(!operationQueue)
{
    operationQueue = [[MyQueue alloc] init];
}
[operationQueue setMaxConcurrentOperationCount:1];
UploadFileOperation *uploadFileOperation = [[UploadFileOperation alloc] initWithObject:someObject];
[operationQueue addOperation:uploadFileOperation];

Now when log the upload progress for two files it shows that both the files are uploading at the same time. Like this: File1 - 17.647026% Uploaded File1 - 18.352907% Uploaded File2 - 0.870381% Uploaded File2 - 1.740762% Uploaded File2 - 2.611142% Uploaded File2 - 3.481523% Uploaded File1 - 19.058788% Uploaded


Complex fetch-request for NSFetchedResultsController


Here's a simplified look for my model:

  • Media has property 'status' that can be either 'Uploading' or 'Uploaded'.
  • User has property 'syncStatus' that be either 'NotSynced' or 'Synced'.
  • ObjectX is a 'linking' object between User and Media
  • User has to-many relationship to ObjectX
  • ObjectX has to-one relationship to Media

Is there any way to use NSFetchedResultsController to fetch all Users that are 'Synced' and whose all media are 'Uploaded'? It would have to update its content also when 'Media' status is changed so that new User should be fetched. I've heard NSFetchedResultsController doesn't work well with such complex fetch requests.

Model Graph


Define iOS Bundle Identifier in a header file


I am trying to maintain two bundle identifiers for the same app: one for the development state, another for the AppStore. This allows me to have both the 'official' version and the development version installed on the exact same device without conflict.

What I need is a simple way to control the bundle identifier through a header file. In Xcode, I have specified the following settings:

  1. Preprocess Info.plist File set to Yes;
  2. Info.plist Preprocessor Prefix File set to ux_defines.h.

The ux_defines.h goes as follows:

// Set this to 0 to switch bundle id to official
#define USE_DEBUG_PRODUCT          1


#if (USE_DEBUG_PRODUCT == 1)
#  define MACRO_APPID com.companyname.appname_dbg
#else
#  define MACRO_APPID com.companyname.appname
#endif

In Info.plist, I have specified the Bundle Identifier as follows:

<key>CFBundleIdentifier</key>
<string>MACRO_APPID</string>

However, when I build for the device, Xcode always gives me an error: Failed to code sign "App Name". On the other hand, everything works smoothly if I keep the bundle identifier hard-coded but define a custom option in Info.plist. For example, the following option:

<key>FooBar</key>
<string>MACRO_APPID</string>

...is correctly preprocessed into:

<key>FooBar</key>
<string>com.companyname.appname_dbg</string>

... or

<key>FooBar</key>
<string>com.companyname.appname</string>

... depending on the value of MACRO_APPID in the header. The error seems only specific to the bundle identifier.

How can I set up the project and avoid these errors?